此代码定义了一个非常简单的特征,用于表示二叉树和实现该特征的结构:
pub trait BTree<T> {
fn all(&self) -> Option<(&Self, &Self, &T)>;
fn left(&self) -> Option<&Self>;
fn right(&self) -> Option<&Self>;
fn value(&self) -> Option<&T>;
}
pub struct MyBTree<T> {
opt: Option<Box<(MyBTree<T>, MyBTree<T>, T)>>,
}
impl<T> BTree<T> for MyBTree<T> {
fn all(&self) -> Option<(&Self, &Self, &T)> {
match self.opt {
None => None,
Some(ref tuple) => Some((&tuple.0, &tuple.1, &tuple.2)),
}
}
fn left(&self) -> Option<&Self> {
match self.all() {
None => None,
Some((left, _, _)) => Some(left),
}
}
fn right(&self) -> Option<&Self> {
match self.all() {
None => None,
Some((right, _, _)) => Some(right),
}
}
fn value(&self) -> Option<&T> {
match self.all() {
None => None,
Some((_, _, value)) => Some(value),
}
}
}
Run Code Online (Sandbox Code Playgroud)
实现left,right并且value可以在特征内部移动,因为它们仅取决于all特征定义的方法,而不依赖于实现细节.
这适用于value,但不与left和right.例如,如果我尝试移动left特征体中的实现,我会得到以下编译错误:
error[E0311]: the parameter type `T` may not live long enough
--> src/lib.rs:6:24
|
6 | match self.all() {
| ^^^
|
= help: consider adding an explicit lifetime bound for `T`
note: the parameter type `T` must be valid for the anonymous lifetime #1 defined on the method body at 5:9...
--> src/lib.rs:5:9
|
5 | / fn left(&self) -> Option<&Self> {
6 | | match self.all() {
7 | | None => None,
8 | | Some((left, _, _)) => Some(left),
9 | | }
10| | }
| |_________^
note: ...so that the reference type `&T` does not outlive the data it points at
--> src/lib.rs:6:24
|
6 | match self.all() {
|
Run Code Online (Sandbox Code Playgroud)
为什么这个问题出现在特征中而不是在实现中MyBTree?
为什么编译器抱怨的一生T中谁的方法忽略 T值-而它与方法的工作value ,其确实在它的返回类型提T'
dto*_*nay 11
为什么这个问题出现在特质中,而不是在MyBTree的实现中?
当您考虑实现BTree<T>具有生命周期的类型时,这些方法签名会变得更加细微.我对涉及泛型类型参数或Self类型的所有生命周期错误的一般建议是:关注类型为借用类型的情况.
借用类型的问题是,您永远不会拥有比其引用的数据更长的生命周期的引用.这个原则最简单的例子是:
fn f<'a, 'b>() {
// error[E0491]: in type `&'a &'b ()`, reference has a longer
// lifetime than the data it references
let _: &'a &'b ();
}
Run Code Online (Sandbox Code Playgroud)
Rust强制我们保证引用引用的数据超过引用,在这种情况下为'boutlives 'a.
fn f<'a, 'b: 'a>() {
let _: &'a &'b ();
}
Run Code Online (Sandbox Code Playgroud)
现在让我们BTree通过考虑如果T是借用类型的错误,将其应用于您的情况&().首先,查看您放入的以下两种方法impl<T> BTree<T> for MyBTree<T>.我明确地写了明确的生命时间来澄清讨论.
impl<T> BTree<T> for MyBTree<T> {
fn left<'a>(&'a self) -> Option<&'a Self> { /* ... */ }
fn value<'a>(&'a self) -> Option<&'a T> { /* ... */ }
}
Run Code Online (Sandbox Code Playgroud)
为了让调用者能够调用left,他们必须知道Self生命的终结'a.并且为了让调用者能够调用value它们必须知道Self寿命超过寿命'a 并且 T寿命更长'a(为了&'a T成为有意义的类型,如上所述).借用检查器不会让他们调用这些方法,除非满足这些要求,因此实现可以假设满足这些要求.
此外,借用检查器可以看到,如果 Self outlives 'a 然后也T寿命更长,'a因为MyBTree<T>包含类型的值T.
这就是实施left和value内部没有问题的原因impl<T> BTree<T> for MyBTree<T>.呼叫者和MyBTree<T>结构共同保证一切都在我们需要的时候生存.
现在我们在BTree<T>特征定义中有这些方法.
trait BTree<T> {
fn left<'a>(&'a self) -> Option<&'a Self> { /* ... */ }
fn value<'a>(&'a self) -> Option<&'a T> { /* ... */ }
}
Run Code Online (Sandbox Code Playgroud)
事情错在这里,因为如果调用者调用left他们必须知道Self会超越'a,但他们都不能保证这T会超越'a.例如,它们可能具有T=&'b ()一些完全不相关的较短寿命'b.正如我们在上面所看到的那样,这将&'a T等于&'a &'b ()不属于合法类型的那个.
Rust value对特性中定义的满意的原因是调用者保证输入生命周期Self和T寿命都长'a.Rust left对特征中定义的不满意的原因是调用者只保证Selfoutlives 'a,而不是实现所假设的Toutlives 'a.
为什么编译器会在忽略 T值的方法中抱怨T的生命周期- 虽然它适用
value于在返回类型中提到T 的方法?
那么错误不是关于返回值,而是关于调用all().仔细看.
error[E0311]: the parameter type `T` may not live long enough
--> src/lib.rs:6:24
|
6 | match self.all() {
| ^^^
Run Code Online (Sandbox Code Playgroud)
为了调用all(),调用者负责证明输入和输出类型是有效类型.但在T类似的情况下&'b (),这可能不是真的.在all()将返回&'a &'b ()所以借检查防止呼叫.
我们可以通过明确我们的实现假定的保证来解决这个问题,在这种情况下,这种保证会更T长久'a.
trait BTree<T> {
fn left<'a>(&'a self) -> Option<&'a Self>
where
T: 'a,
{
/* ... */
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
188 次 |
| 最近记录: |