【发布时间】:2018-08-08 15:03:33
【问题描述】:
这段代码定义了一个非常简单的特征来表示二叉树和一个实现该特征的结构:
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),
}
}
}
left、right 和 value 的实现可以移动到 trait 内部,因为它们只依赖于 trait 定义的 all 方法,而不依赖于实现细节。
这适用于value,但不适用于left 和right。例如,如果我尝试将 left 的实现移动到 trait 的主体中,我会收到以下编译错误:
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() {
|
为什么这个问题出现在 trait 中而不是在 MyBTree 的实现中?
为什么编译器在忽略 T 值的方法中抱怨T 的生命周期——而它与确实的方法value 一起工作在其返回类型中提及 T?
【问题讨论】:
-
代码 compiles 和 non lexical lifetimes
#![feature(nll)] -
是的,核心区别似乎是 NLL 允许引用不超过引用的数据。
fn f<'a, 'b>() { let _: &'a &'b (); } -
如果你使用an associated type instead of a type parameter,那么它会编译。除非有理由认为单个类型应该能够实现
BTree特征的多个实例,否则我建议您改用关联的类型版本。这样,当您使用BTree编写泛型函数时,您将不需要为BTree的T添加额外的类型参数。 -
@FrancisGagné 你说得对,关联类型在这里可能更好;我仍然不太擅长在这些参数和类型参数之间进行选择。感谢您指出了这一点。话虽如此,我还不清楚为什么关联类型没有与类型参数相同的生命周期问题...:-/