具有特征的类型定义:指定显式生命周期界限的差异?

时间:2014-12-28 10:29:22

标签: types rust traits

我在类型定义中使用特征时遇到了解生命周期限制要求的问题。例如:

trait Kind { /* ... */ }
type CollectionOfKind<'a> = Vec<&'a Kind>;
// => error: explicit lifetime bound required

对于结构中的特征(Answer 1Answer 2),已经讨论了有效寿命限制的要求。起初,我在应用&#34;添加生命周期&#34;的方法时遇到了问题。在这里,因为这不起作用:

type CollectionOfKind<'a> = Vec<&'a Kind + 'a>;
type CollectionOfKind<'a> = Vec<&'a Kind + 'static>;

但是,这只是一个语法问题,因为@Shepmaster指出了precedence of plus

总的来说,我现在已经找到了三种指定生命周期边界的方法:

// Version 1: Adding 'static to the trait itself
trait Kind : 'static { /* ... */ }
type CollectionOfKind<'a> = Vec<&'a Kind>;
// Version 2: Adding 'static to the type definition
trait Kind { /* ... */ }
type CollectionOfKind<'a> = Vec<&'a (Kind + 'static)>;
// Version 3: Adding the lifetime of the reference to the trait object (?)
trait Kind { /* ... */ }
type CollectionOfKind<'a> = Vec<&'a (Kind + 'a)>;

我不明白:这三种情况之间的确切区别是什么?

我的问题:

为了看到差异,我试图理解其他答案中提到的某些要点。例如,在上面链接的答案2中,我发现了以下提示,我不完全理解:

  

在这种情况下,'static要求底层对象必须是真正的结构或&'static引用,但不允许其他引用。

底层对象必须是真实的&#34;意味着什么?结构?如果没有&#34;真实&#34;?

,结构如何实现特征是可能的

同样对于@Shepmaster引用的引用:

  

您必须指定生命周期两次:一次用于引用的生命周期,一次用于trait对象本身,因为traits可以用于引用,如果底层对象是引用,则必须指定其生命周期同样。

说实话,我不明白为什么必须指定两次。我虽然通过对实现特定特征的对象的引用来定义特征对象。所以根据定义(?)是一个参考,因此,无论如何都有生命周期?

1 个答案:

答案 0 :(得分:4)

回答新问题

你真的有两个正交的情况。我将首先解决更容易的问题,即#2和#3的区别。评论与我希望的代表性示例相符:

trait Kind { 
    fn trait_fn(&self) -> u8 { 0 }
}

type CollectionOfKind1<'a> = Vec<&'a (Kind + 'static)>;
type CollectionOfKind2<'a> = Vec<&'a (Kind + 'a)>;

struct Alpha;
impl Kind for Alpha {}

struct Beta<'b> {
    name: &'b str,
}
impl<'a> Kind for Beta<'a> {}

fn main() {
    let name = "world".to_string();

    // Doesn't need/have it's own lifetime.
    let a = Alpha;
    // Has a reference to something with the 'static lifetime.
    let b1 = Beta { name: "hello" };
    // Has a reference to something with the lifetime of `name`,
    // which is less than 'static.
    let b2 = Beta { name: &name[..] };  

    // Our vector is composed of references to
    // things that *might* have a reference themselves!
    let mut c1: CollectionOfKind1 = Vec::new();
    c1.push(&a);
    c1.push(&b1);
    // c1.push(&b2); // error: `name` does not live long enough

    let mut c2: CollectionOfKind2 = Vec::new();
    c2.push(&a);
    c2.push(&b1);
    c2.push(&b2); // Hooray
}

值得注意的是,的生命周期不必相同!你可以写:

type CollectionOfKind2<'a, 'b> = Vec<&'a (Kind + 'b)>;

第二件事是trait Foo : 'static的含义。我在这里不太确定,但我写了这个小例子:

trait Foo : 'static {}

fn x(a: &Foo) {}

fn main() {
    x(&3u8);
}

使用

进行编译时出现此错误
  

必须为对象类型Foo

的强制转换实现特征Foo + 'static

基于此,我认为Foo : 'static只是写Foo + 'static的另一种方式。我能想到的主要区别在于它限制了永远在非'static生命周期的结构上实现的特性:

struct B<'a> {
    b: &'a str,
}

impl<'a> Foo for B<'a> {}

有错误

  

声明生命周期限制不满足[...]但是生命周期参数必须比静态生命周期更长

原始答案

我看到你已经发现了这个,但你可能想要更新你的Rust版本。如果我在Playrasn上编译你的代码,我会得到一个关于如何修复它的建议:

error: expected a path on the left-hand side of `+`, not `&'a Kind` [E0178]
type CollectionOfKind<'a> = Vec<&'a Kind + 'a>;
                                ^~~~~~~~
note: perhaps you meant `&'a (Kind + 'a)`? (per RFC 438)
type CollectionOfKind<'a> = Vec<&'a Kind + 'a>;
                                ^~~~~~~~

引用RFC 438, Precedence of Plus