[英]Type definition with a trait: Differences of specifying an explicit lifetime bound?
当我在类型定义中使用特征时,我在理解生命周期绑定要求时遇到问题。 例如:
trait Kind { /* ... */ }
type CollectionOfKind<'a> = Vec<&'a Kind>;
// => error: explicit lifetime bound required
已经针对结构中的特征(答案 1 ,答案 2 )讨论了对生命周期边界的要求。 起初,我在这里完全无法应用“添加生命周期”的方法,因为这不起作用:
type CollectionOfKind<'a> = Vec<&'a Kind + 'a>;
type CollectionOfKind<'a> = Vec<&'a Kind + 'static>;
但是,由于@Shepmaster 指出的加号优先,这只是一个语法问题。
总的来说,我现在找到了三种指定生命周期界限的方法:
// 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
引用,但不允许其他引用。
底层对象必须是“真实”结构体是什么意思? 一个结构如何实现特性而不是“真实的”?
同样对于@Shepmaster 引用的引用:
你必须指定两次生命周期:一次是引用的生命周期,一次是 trait 对象本身,因为 trait 可以为引用实现,如果底层对象是引用,你也必须指定它的生命周期。
老实说,我不明白为什么必须指定两次。 我虽然 trait 对象是通过对实现某个 trait 的对象的引用来定义的。 所以它根据定义(?)是一个引用,因此,无论如何都有生命周期?
你真的有两个正交的情况。 我将首先解决更简单的问题,即 #2 和 #3 的区别。 评论符合我希望是一个代表性的例子:
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
}
这里需要注意的是,生命周期不必相同! 你可以写:
type CollectionOfKind2<'a, 'b> = Vec<&'a (dyn Kind + 'b)>;
第二件事是trait Foo : 'static
的含义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 版本。 如果我在 Playpen 上编译您的代码,我会收到有关如何修复它的建议:
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>;
^~~~~~~~
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.