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

3
我希望为下面这个结构体编写一个初始化器。
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 }
}

这也不起作用,因为我猜我们只是借用了值而没有转移所有权,这将在new返回后仍然释放bar
在这种情况下,我是否被迫在结构体中使用Box
编辑:请注意,需要引用的原因是因为在我的情况下,Bar实际上是一个通用特征,因此大小可能会变化,这意味着在堆栈上分配内存是行不通的。

这个问题已经在Reddit上同时发布了。 - Shepmaster
2个回答

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

编译器应该对此进行单态化处理,基本上与手动编写代码的速度一样快。这也允许将所有内容分配到堆栈上。


3

不了解Bar的具体内容很难确定,如果它是一个特征(trait),那么确实需要使用&Bar或者Box<Bar>。如果它只是一个普通的类型,则通常的做法是直接对其进行存储:

struct Foo {
    bar: Bar
}

当你听到使用&Bar更加灵活时,通常是在函数参数方面,例如fn func(bar: &Bar),但即使如此,这也取决于你实际要做的事情。然而,在定义结构体字段时,直接存储值通常是你想要的,除非你知道自己在做什么。这清楚地表明了Foo拥有Bar

是的,这是一个特征,实际上是通用的,因此大小可能会有所不同,这就是为什么首先需要引用的原因。有什么想法吗? - IluTov
1
是的,在这种情况下,据我所知,您必须提供一个比初始化程序更长寿的引用,因此它必须作为参数传递到初始化程序中。否则,是的,您必须使用Box,因为在这种情况下,生命周期不会起作用,因为您将完全将其移动到新结构中。 - Jorge Israel Peña

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