为什么结构中的Box <t>需要“显式生命周期约束”</t>

时间:2014-09-21 12:16:05

标签: rust rust-obsolete

  

编者注:在RFC 599实施后,此代码不再产生相同的错误,但答案中讨论的概念仍然有效。

我正在尝试编译此代码:

trait A {
    fn f(&self);
}

struct S {
    a: Box<A>,
}

我收到此错误:

a.rs:6:13: 6:14 error: explicit lifetime bound required
a.rs:6     a: Box<A>,

我希望S.a拥有A的实例,并且不知道这个生命周期是如何合适的。我需要做些什么才能使编译器满意?

My Rust版本:

rustc --version
rustc 0.12.0-pre-nightly (79a5448f4 2014-09-13 20:36:02 +0000)

2 个答案:

答案 0 :(得分:21)

(稍微迂腐一点:A是一个特质,因此S不拥有 A 的实例,它拥有一个盒装实例<实现A 的某种类型的em>。)

特征对象表示具有某种未知类型的数据,也就是说,唯一知道的数据是它实现了特征A。由于类型未知,编译器无法直接推断所包含数据的生命周期,因此要求在trait对象类型中明确说明此信息。

这是通过Trait+'lifetime完成的。最简单的方法是使用'static,即完全禁止存储因范围而变得无效的数据:

a: Box<A + 'static>

以前,(在引入有生命限制的特征对象和此explicit lifetime bound required错误消息的可能性之前),所有盒装特征对象都是隐式'static,也就是说,这种限制形式是唯一的选择。

最灵活的形式是在外部暴露生命周期:

struct S<'x> {
    a: Box<A + 'x>
}

这允许S存储实现A的任何类型的特征对象,可能对S有效的范围有一些限制(即'x的类型{ {1}}小于'static S对象将被困在某个堆栈框架内。)

答案 1 :(得分:18)

这里的问题是也可以为引用实现特征,所以如果你没有为Box指定所需的生命周期,那么任何东西都可以存储在那里。

您可以在此rfc中查看有关生命周期的要求。

所以一种可能的解决方案是绑定生命周期Send(我把我放在S中):

trait A {
    fn f(&self);
}

struct I;

impl A for I {
    fn f(&self) {
        println!("A for I")
    }
}

struct S {
    a: Box<A + Send>
}

fn main() {
    let s = S {
        a: box I
    };
    s.a.f();
}

另一个是将生命周期设置为'a(我们可以将参考&amp; I或I设置为S):

trait A {
    fn f(&self);
}

struct I;

impl A for I {
    fn f(&self) {
        println!("A for I")
    }
}

impl <'a> A for &'a I {
    fn f(&self) {
        println!("A for &I")
    }
}

struct S<'a> {
    a: Box<A + 'a>
}

fn main() {
    let s = S {
        a: box &I
    };
    s.a.f();
}

请注意,这是更通用的,我们可以存储引用和拥有数据(Send类,其生命周期为'static),但是在使用类型的任何地方都需要一个生命周期参数。