具有特征的类型定义:指定显式生命周期界限的差异? [英] Type definition with a trait: Differences of specifying an explicit lifetime bound?

查看:46
本文介绍了具有特征的类型定义:指定显式生命周期界限的差异?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我在类型定义中使用特征时,我在理解生命周期绑定要求方面遇到问题.例如:

I'm having issues understanding the lifetime bound requirements when I use a trait in a type definition. For instance:

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

已经针对结构中的 trait 的情况讨论了生命周期边界的要求(答案 1答案 2).起初,我在这里完全无法应用添加生命周期"的方法,因为这不起作用:

The requirement for lifetime bounds has already been discussed for the case of a trait within a struct (Answer 1, Answer 2). At first, I had problems to apply the approach of "adding the lifetime" here at all, since this does not work:

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

然而,这只是一个语法问题,因为 @Shepmaster 指出的加号优先级.

However, this was only a syntax issue, due to the precedence of plus as pointed out by @Shepmaster.

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

Overall, I now have found three ways to specify the lifetime bounds:

// 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)>;

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

What I don't understand: What is the exact difference between these three cases?

我的问题:

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

In order to see the differences, I was trying to understand certain points mentioned in the other answers. For instance in the above linked Answer 2, I have found the following hint which I do not fully understand:

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

In this case, the 'static requires that the underlying object must be a real struct, or a &'static reference, but other references won't be allowed.

底层对象必须是真实"结构体是什么意思?一个结构如何实现特性而不是真实的"?

What does it mean that the underlying object must be a "real" struct? How is it possible for a struct to implement the trait without being "real"?

类似于@Shepmaster 引用的引用:

Similarly for the quote that @Shepmaster has cited:

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

You have to specify the lifetime two times: once for the lifetime of the reference, and once for the trait object itself, because traits can be implemented for references, and if the underlying object is a reference, you must specify its lifetime as well.

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

To be honest, I don't see why it must be specified twice. I though a trait object is defined by being a reference to an object which implements a certain trait. So it is by definition (?) a reference, and thus, has a lifetime anyways?

推荐答案

回答新问题

你真的有 两种正交情况 .我将首先解决更简单的问题,即 #2 和 #3 的区别.评论符合我希望是一个有代表性的例子:

Answer for new question

You really have two orthogonal cases . I'll tackle the easier one first, the difference of #2 and #3. Comments are inline with what I hope is a representative example:

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

type CollectionOfKind1<'a> = Vec<&'a (dyn Kind + 'static)>;
type CollectionOfKind2<'a> = Vec<&'a (dyn 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
}

这里需要注意的是,生命周期不必相同!你可以写:

Of note here is that the lifetimes don't have to be the same! You could have written:

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

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

The second thing is the meaning of trait Foo : 'static. I'm less sure here, but I wrote this small example:

trait Foo : 'static {}

fn x(a: &Foo) {}

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

编译时出现这个错误

必须实现特征 Foo 才能转换为对象类型 Foo + 'static

the trait Foo must be implemented for the cast to the object type Foo + 'static

基于此,我认为 Foo : 'static 只是 Foo + 'static 的另一种写法.我能想到的主要区别在于,它限制了在具有非 'static 生命周期的结构上实现的 trait ever:

Based on that, I think that Foo : 'static is just another way of writing Foo + 'static. The main difference I can think of is that it restricts the trait from ever being implemented on a struct with non-'static lifetimes:

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

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

有错误

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

declared lifetime bound not satisfied [...] but lifetime parameter must outlive the static lifetime

原答案

我看到你已经发现了这一点,但你可能想要更新你的 Rust 版本.如果我在 Playpen 上编译您的代码,我会收到有关如何修复它的建议:

Original answer

I see you've found this out already, but you may want to update your version of Rust. If I compile your code on the Playpen, I get a suggestion on how to fix it:

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,Plus 的优先级.

这篇关于具有特征的类型定义:指定显式生命周期界限的差异?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆