22

编者注:此代码在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,并且看不到该生命周期在这里如何合适。我需要做什么才能让编译器满意?

我的锈版本:

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

2 回答 2

25

(有点迂腐的观点:这A是一个特征,所以S不是拥有 的实例A,而是拥有某种类型的盒装实例,它实现了A。)

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

这是通过Trait+'lifetime. 最简单的方法是只使用'static,也就是说,完全禁止存储可能由于范围而变得无效的数据:

a: Box<A + 'static>

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

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

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

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

于 2014-09-21T13:40:16.747 回答
21

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

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

所以一种可能的解决方案是绑定生命周期Send(我们把 I 放在 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(我们可以将引用 &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的类型),但在使用该类型的任何地方都需要生命周期参数。

于 2014-09-21T13:37:46.690 回答