Rust 支持特征继承,如下:
pub trait A {}
pub trait B: A {}
B: A
表示如果某个类型T
实现了B
,那么它也需要实现A
中的所有方法。
但是今天我看到以下代码:
trait Display: 'static {
fn print(&self);
}
这是什么意思?好像不是特质遗传。
Rust 支持特征继承,如下 [...]B:A 意味着如果某个类型 T 实现了 B,那么它也需要实现 A 中的所有方法。
从技术上讲,这不是继承,而是要求。它是一个“特征绑定”,与函数中的特征绑定并不完全不同:它将 B 实现的类型“可实现”限制为仅已实现 A 的类型。 随着措辞的改变,第二个版本更容易理解:它是一个生命周期界限,这意味着它将 B 可实现的类型限制为仅具有
'static
生命周期的类型,这意味着如果您尝试实现B 类型,必须要么根本没有生命周期,要么有 'static
生命周期(或者实现必须有生命周期限制,即仅适用于
该类型的一些用途)。您可以看到,如果您尝试在生命周期通用结构上实现该特征:
struct A<'a>(&'a str);
trait Display: 'static {
fn print(&self);
}
impl <'a>Display for A<'a> {
fn print(&self) { todo!() }
}
将会产出
错误[E0478]:不满足生命周期限制
这是因为可以是任何东西,因此为
'a
Display
实现
A<'a>
意味着它也适用于非 'static
实例,这是无效的。通过在 impl上添加相关的生命周期界限,从而将实现限制为
A<'static>
实例:
struct A<'a>(&'a str);
trait Display: 'static {
fn print(&self);
}
impl <'a: 'static>Display for A<'a> {
fn print(&self) { todo!() }
}
,并且实现是有效的(注意:这里不需要
'a
,你可以只是impl ... for A<'static>
,我展示它是为了规律性)。
'static
:
struct A(String);
trait Display: 'static {
fn print(&self);
}
impl Display for A {
fn print(&self) { todo!() }
}
Rust 没有继承性。
在您的情况下,约束是
生命周期。
要实现您的 Display
特征,对象可以包含引用,但在这种情况下,它们的生命周期必须遵守此约束。
假设您有这种类型:
struct S<'a> {
s: &'a str,
}
那么你就无法在任何生命周期中实现该特质,而只能实现
'static
。
impl Display for S<'static> {
fn print(&self){}
}
fn main() {
let s1 = "test";
let a = S { s: s1 };
a.print(); // compiles
let s2 = "test".to_string();
let a = S { s: &s2 };
a.print(); // doesn't compile because s doesn't live long enough
}
虽然其他答案已经提到这是一个Lifetime Bound
'a
“特征”/生命周期界限由所有类型满足,
不包含可能比“a短”的引用。
仅此而已。'static
只是一种特殊情况,满足所有类型,
不包含将永远
变得无效的引用。这里有一个例子说明为什么这个概念是有用/必要的:
// Basic definitions for demo purposes
trait Foo {
fn get_value(&self) -> &i32;
}
struct Bar<'a>{
value: &'a i32
}
impl<'a> Foo for Bar<'a>{
fn get_value(&self) -> &i32 {
self.value
}
}
// Now, this seemingly innocent method already cannot be allowed by the compiler.
// As for why, see below in `main`
fn push_foo(tgt: &mut Vec<Box<dyn Foo>>, foo: impl Foo) {
tgt.push(Box::new(foo));
}
// demonstration why `push_foo` must be illegal:
fn main() {
let mut list_of_foos = Vec::new();
{
let value = 42;
let bar = Bar { value: &value };
push_foo(&mut list_of_foos, bar);
}
// `value` went out of scope at this point, so this would be a use after free bug
// therefore, the `push_foo` function cannot be allowed to compile
let _access_value_after_scope_ended = *list_of_foos[0].get_value();
}
// The simple fix for this issue is to force `foo` to not contain any
// data that has *any* additional lifetime bounds (== `foo` shall satisfy the 'static Lifetime Bound).
// (The `Box<dyn Foo>` in this signature is a shorthand for `Box<dyn Foo + 'static>`)
fn push_foo_fixed_v1(tgt: &mut Vec<Box<dyn Foo>>, f: impl Foo + 'static) {
tgt.push(Box::new(f));
}
// To fix the problem more generally, we could express the following additional guarantee:
// There exists a lifetime `'a` that is longer than any Lifetime Bound on
// `foo` or any of the `dyn Foo`s in `tgt`:
fn push_foo_fixed_v2<'a>(tgt: &mut Vec<Box<dyn Foo + 'a>>, f: impl Foo + 'a) {
tgt.push(Box::new(f));
}
[
铁锈游乐场]