当我们让一个特质继承“static”时,这意味着什么?

问题描述 投票:0回答:3

Rust 支持特征继承,如下:

pub trait A {}
pub trait B: A {}

B: A
表示如果某个类型
T
实现了
B
,那么它也需要实现
A
中的所有方法。

但是今天我看到以下代码:

trait Display: 'static {
    fn print(&self);
}

这是什么意思?好像不是特质遗传。

rust static traits lifetime
3个回答
6
投票

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 没有继承性。

5
投票

在您的情况下,约束是

生命周期

要实现您的 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

0
投票

生命周期实际上是一种特殊的(自动)特征。


'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)); }

[

铁锈游乐场
 ]

© www.soinside.com 2019 - 2024. All rights reserved.