如何初始化包含引用的结构?

时间:2015-02-15 10:46:21

标签: initialization rust lifetime

我想为以下结构编写初始化器。

struct Foo {
    bar: &Bar
}

建议使用&T而不是Box<T>来提高灵活性,这就是我在这里要做的事情。没有初始化器,你就可以使用这样的结构。

{
    let bar = ...;
    let foo = Foo { bar: bar };

    // use foo    

    // dealloc bar and foo
}

这很有效。但我想在初始化程序中分配&Bar。现在显然在堆栈上分配bar将不起作用,因为一旦初始化器返回它就超出了范围。所以我想我可以使用Box

fn new() -> Foo {
    let bar = Box::new(...);
    Foo { bar: &*bar }
}

这也不起作用,因为我猜我们只是借用价值而不是转移所有权,一旦bar返回,仍会解除分配new

在这种情况下,我是否被迫在结构中使用Box

修改

注意:需要引用的原因是因为Bar在我的情况下实际上是一般特征,因此大小可能会有所不同,这意味着堆栈上的分配将无法工作。

2 个答案:

答案 0 :(得分:7)

你的问题确实没有意义。如果您正在new方法中构建对象,那么按照定义您知道类型是什么(因为您正在调用该构造函数),并且您不需要对待它作为一个特质对象。你应该只使用类型!

  

需要引用的原因是因为Bar在我的情况下实际上是一般特征,因此大小可以变化,这意味着堆栈上的分配不会起作用。

这不完全正确!如果您想接受参数,并且想要转移所有权,那么您可以简单地将类型限制为您想要的特征:

trait Talker { fn talk(&self); }

struct Dog;
impl Talker for Dog { fn talk(&self) { println!("Woof") }}

struct Cat;
impl Talker for Cat { fn talk(&self) { println!("Meow") }}

struct OwnAGeneric<T: Talker> {
    t: T
}

impl<T: Talker> OwnAGeneric<T> {
    fn new(t: T) -> OwnAGeneric<T> { OwnAGeneric { t: t } }

    fn talk(&self) { println!("I own this:"); self.t.talk(); }
}

fn main() {
    let owned_cat = OwnAGeneric::new(Cat);  
    owned_cat.talk();
}

这应该由编译器单态化,并且基本上与您手动编写代码一样快。这也允许在堆栈上分配所有内容。

答案 1 :(得分:3)

在不知道Bar是什么的情况下,很难确定。如果它是一个特征,那么它需要是&BarBox<Bar>。如果它只是常规类型,那么通常要做的就是直接存储它:

struct Foo {
    bar: Bar
}

当您听说&Bar首选灵活性时,通常就功能参数而言,例如fn func(bar: &Bar),即使这样,它也取决于你实际做了什么。但是,在结构上定义字段时,直接存储值通常是您想要的,除非您知道自己在做什么。这清楚地表明Foo 拥有 Bar