gpt4 book ai didi

rust - 为什么函数体在结构中编译,而不是在特征中?

转载 作者:行者123 更新时间:2023-11-29 07:43:17 26 4
gpt4 key购买 nike

这段代码定义了一个非常简单的特征来表示二叉树和一个实现该特征的结构:

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),
}
}
}

leftrightvalue 的实现可以移动到 trait 内部,因为它们只依赖于 all 由特征定义的方法,而不是实现细节。

这适用于 value,但 不适用于 leftright。例如,如果我尝试在特征主体中移动 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() {
|

为什么这个问题出现在 trait 而不是 MyBTree 的实现中?

为什么编译器在忽略 T 值的方法中提示 T 的生命周期——而它与方法 value 一起工作> 哪个在其返回类型中提到了 T?

最佳答案

How come this problem occurs in the trait, but not in its implementation for MyBTree?

当您考虑实现 BTree<T> 时,这些方法签名会变得更加微妙对于具有生命周期的类型。我对涉及泛型类型参数或 Self 的所有生命周期错误的一般建议type is:关注类型是借用类型的情况。

借用类型的问题在于,您永远无法拥有比它所引用的数据更长生命周期的引用。此原则的最简单示例是:

fn f<'a, 'b>() {
// error[E0491]: in type `&'a &'b ()`, reference has a longer
// lifetime than the data it references
let _: &'a &'b ();
}

Rust 强制我们保证引用引用的数据比引用更有效,在本例中为 'b超过生命周期'a .

fn f<'a, 'b: 'a>() {
let _: &'a &'b ();
}

现在让我们将其应用到您的 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> { /* ... */ }
}

为了调用者调用left ,他们必须知道 Self生命周期超过生命周期 'a .为了调用者调用 value他们必须知道Self生命周期超过生命周期 'a T生命周期超过生命周期 'a (为了使 &'a T 成为有意义的类型,正如我们在上面看到的)。除非满足这些要求,否则借用检查器不会让他们调用这些方法,因此实现可以假定满足这些要求。

此外,借用检查器可以看到if Self超过生命周期'a 然后还有T超过生命周期'a因为MyBTree<T>包含 T 类型的值.

这就是为什么执行 left 没有问题的原因和 valueimpl<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> { /* ... */ }
}

这里出了问题,因为如果调用者调用 left他们必须知道Self超过生命周期'a ,但他们没有保证 T超过生命周期'a .例如,他们可以有 T=&'b ()对于一些完全不相关的较短生命周期 'b .正如我们在上面看到的,这将使 &'a T等于 &'a &'b ()这不是合法类型。

Rust 对 value 满意的原因特征中定义的是调用者保证SelfT超过输入生命周期 'a . Rust 对 left 不满意的原因特征中定义的是调用者只保证 Self超过生命周期'a , 不是 T超过生命周期'a实现假设。

And how come the compiler complains about the lifetime of T in the methods who ignore the T value -- while it works with the method value which does mention T in its return type?

好吧,错误与返回值无关,而是与对 all() 的调用有关.仔细看。

error[E0311]: the parameter type `T` may not live long enough
--> src/lib.rs:6:24
|
6 | match self.all() {
| ^^^

为了调用all() ,调用者负责证明输入和输出类型是有效类型。但在 T 的情况下类似于 &'b () ,这可能不是真的。 all()会返回 &'a &'b ()所以借用检查器会阻止调用。

我们可以通过明确我们的实现假设的保证来解决这个问题,在这种情况下 T超过生命周期'a .

trait BTree<T> {
fn left<'a>(&'a self) -> Option<&'a Self>
where
T: 'a,
{
/* ... */
}
}

关于rust - 为什么函数体在结构中编译,而不是在特征中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49034550/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com