何时以及如何使用引用向量

10

这段代码正确编译。虽然有一些未使用的代码警告,但目前来说可以忽略。

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());
}

这段代码中重要的部分是push_intstack: Vec<Object<'a>>
我正在尝试制作一个基于堆栈的虚拟机。 我想把状态传递给函数,这些函数可以从堆栈中取出一些东西,操作它们,然后把一些东西放回到堆栈中;命名字段将保存有命名对象。
我有一种直觉,最好将堆栈表示为Vec<&'a Object<'a>>。现在我担心自己犯了一些效率上的错误。我的直觉正确吗?
问题的第二部分是我不知道如何让引用向量版本工作。创建具有正确生命周期的新值以推送到堆栈上对我来说行不通。
关于这个问题我有点模糊,如果我表述不清楚,请问我一些问题以澄清事情。

对于拥有所有权的指针,您需要 Vec<Box<Object<'a>>>。存在效率问题,因为 Object :: Int 占用的空间与 Object :: String 相同,但将其封装只会使情况更糟(即使封箱允许更紧凑的表示方式)。 我会将 Str(String) 更改为 Str(Box<String>),将 Vector<Vec<...>> 更改为 Vector<Box<Vec<...>>>,然后就可以了,因为这样可以消除使 Object 大的唯一因素。 尽管如此,对于更小的(可能更常见的)值来说,额外的间接性可能比低效性更糟糕。 - Veedrac
1
你说的“inefficiency”是什么意思?你是想问如何节约内存还是如何提高性能?另外,我认为这个问题应该发布在http://codereview.stackexchange.com/上。 - oli_obk
@ker 我想我两个都是;我表达含糊是因为我不够了解,无法更具体地说明。是的,它可以提交到代码审查;我不确定。 - phil
1个回答

15
你无法让它起作用的原因是结构体不能有引用其他字段的字段。(请参见底部的支持链接。)
你可以将所有的 Object 放入你的 Vec 中,并让 HashMap 包含它所引用的命名元素的索引。
struct State {
    named: BTreeMap<String, usize>,
    stack: Vec<Object>
}

我也会从你的示例中删除所有生命周期,因为这可以完全使用拥有的对象完成。

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

您可以在Playground中尝试一个工作实现。

支持的链接:

2
关于“(是的,每个单词都是不同的链接)”的样式点。使用其他Stack Overflow问题的项目符号列表更清晰易读,因为SO会自动查找标题并显示它们。 - David J.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接