Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When and how to use a vector of references

This code correctly compiles. It has a few unused code warnings, but that's okay for now.

use std::collections::BTreeMap;

enum Object<'a> {
    Str(String),
    Int(i32),
    Float(f32),
    Vector(Vec<&'a Object<'a>>),
    Prim(fn(State) -> State)
}

struct State<'a> {
    named: BTreeMap<String, &'a Object<'a>>,
    stack: Vec<Object<'a>>

}

impl<'a> State<'a> {
    fn push_int(&mut self, x: i32) {
        self.stack.push(Object::Int(x));
    }
}


fn main() {
    println!("Hello, world!");
    let obj = Object::Str("this is a test".to_string());
}

The important part of this code is push_int and stack: Vec<Object<'a>>.

I'm sort of trying to make a stack-based VM. I want to pass the state to functions, which can take stuff off the stack, manipulate the stuff, and then put some stuff back on the stack; the named field is going to hold named objects.

I have a hunch that it would be better to have the stack represented as a Vec<&'a Object<'a>> instead. The way I have it now, I fear I'm committing some inefficiency error. Is my hunch correct?

The second part of the problem is that I don't know how to get the vector of references version to work. Creating new value with the right lifetimes to push onto the stack is not working for me.

I'm a bit vague about this issue, so if I've been unclear, ask me questions to clear stuff up.

like image 767
phil Avatar asked Nov 09 '15 00:11

phil


1 Answers

The reason you could not get it to work is that structs cannot have fields that refer to other fields. (See supporting links at the bottom.)

What you can do, is put all the Objects into your Vec, and have the HashMap contain the indices of the named elements it references.

struct State {
    named: BTreeMap<String, usize>,
    stack: Vec<Object>
}

I'd also remove all lifetimes from your example, as this can be done completely with owned objects.

enum Object {
    Str(String),
    Int(i32),
    Float(f32),
    Vector(Vec<Object>),
    Prim(fn(State) -> State)
}

You can try out a working implementation in the Playground

Supporting links:

  • How to initialize struct fields which reference each other

  • using self in new constructor

  • How to design a struct when I need to reference to itself

  • How to store HashMap and its Values iterator in the same struct?

  • What lifetimes do I use to create Rust structs that reference each other cyclically?

  • How to store a SqliteConnection and SqliteStatement objects in the same struct in Rust?

  • Why can't I store a value and a reference to that value in the same struct?

  • https://stackoverflow.com/questions/33123634/reference-inside-struct-to-object-it-owns

like image 66
oli_obk Avatar answered Oct 17 '22 15:10

oli_obk