gpt4 book ai didi

rust - 在 impl 或方法上指定生命周期参数有什么区别?

转载 作者:行者123 更新时间:2023-11-29 07:42:28 25 4
gpt4 key购买 nike

在 Rust 1.3.0 中,Deref trait 在文档中具有以下签名:

pub trait Deref {
type Target: ?Sized;
fn deref(&'a self) -> &'a Self::Target;
}

我会在不命名生命周期的情况下实现它,因为它们无论如何都会被删除。然而,在 docs example它看起来像这样:

use std::ops::Deref;

struct DerefExample<T> {
value: T
}

impl<T> Deref for DerefExample<T> {
type Target = T;

fn deref<'a>(&'a self) -> &'a T {
&self.value
}
}

fn main() {
let x = DerefExample { value: 'a' };
assert_eq!('a', *x);
}

这一切都很好,但是如果我在 impl 而不是方法上指定生命周期参数 'a:

struct DerefExample<T> {
value: T
}

impl<'a, T> Deref for DerefExample<T> {
type Target = T;

fn deref(&'a self) -> &'a T {
&self.value
}
}

我收到以下错误:

error[E0308]: method not compatible with trait
--> src/main.rs:10:5
|
10 | / fn deref(&'a self) -> &'a T {
11 | | &self.value
12 | | }
| |_____^ lifetime mismatch
|
= note: expected type `fn(&DerefExample<T>) -> &T`
found type `fn(&'a DerefExample<T>) -> &'a T`
note: the anonymous lifetime #1 defined on the method body at 10:5...
--> src/main.rs:10:5
|
10 | / fn deref(&'a self) -> &'a T {
11 | | &self.value
12 | | }
| |_____^
note: ...does not necessarily outlive the lifetime 'a as defined on the impl at 7:1
--> src/main.rs:7:1
|
7 | / impl<'a, T> Deref for DerefExample<T> {
8 | | type Target = T;
9 | |
10 | | fn deref(&'a self) -> &'a T {
11 | | &self.value
12 | | }
13 | | }
| |_^

这让我很困惑。该方法的签名与文档中的签名没有什么不同。此外,我认为在 impl 上或直接在方法上指定生命周期参数的区别仅在于参数的范围,因此它可以在整个 impl block 中使用,而不仅仅是在方法中使用。我在这里缺少什么?

最佳答案

是的,有区别。

The method's signature is no different than the one from the docs.

在 docs 中它看起来像这样的事实是 rustdoc 的错误,并且已经被解决。

如果您点击文档右上角的[src]链接,您将被重定向到Deref的实际源代码,如下所示(我删除了额外的属性和评论):

pub trait Deref {
type Target: ?Sized;
fn deref<'a>(&'a self) -> &'a Self::Target;
}

可以看到 deref() 声明了一个生命周期参数。

I thought that the difference between specifying the lifetime parameter on the impl or on the method directly is in the scope of the parameter only.

这是错误的。区别不仅仅在于范围。我不认为我能够提供令人信服的并排示例,其中语义差异是可见的,但请考虑以下推理。

首先,生命周期参数与泛型类型参数没有区别。他们使用相似的声明语法并非巧合。像泛型参数一样,生命周期参数参与方法/函数签名,所以如果你想实现一个具有生命周期参数的方法的特征,你的实现必须也有相同的生命周期参数(模数可能重命名)。

其次,impl 签名中的生命周期参数用于表达不同于函数的生命周期关系。对于方法,总是调用者决定他们想要使用的实际生命周期参数。它再次类似于泛型方法的工作方式——调用者可以用他们需要的任何类型实例化其类型参数。这非常重要,特别是对于 Deref - 您可能希望任何实现 Deref 的东西都可以在调用该方法的引用的生命周期内被取消引用,而不是其他东西.

然而,对于 impl,生命周期参数不是在调用使用此参数的方法时选择的,而是在编译器选择适当的 impl 时选择的。它可能会根据值的类型这样做(并且通常会这样做),这会阻止用户在调用该方法时指定任意生命周期。例如:

struct Bytes<'a>(&'a [u8]);

impl<'a> Bytes<'a> {
fn first_two(&self) -> &'a [u8] {
&self.0[..2]
}
}

此处,first_two() 方法返回一个切片,其生命周期为存储在 Bytes 结构中的值。方法的调用者无法决定他们想要哪个生命周期——它始终固定为调用此方法的结构内切片的生命周期。在保持相同语义的同时将生命周期参数降低到方法中也是不可能的,我想你能明白为什么。

在您的情况下,您指定的生命周期参数既不参与 impl 的签名也不参与任何关联类型,因此理论上可以像它一样使用分别在每个函数上声明(因为在调用方法时它可以是任意的),但是关于方法签名的推理(上面提供的)开始了。

关于rust - 在 impl 或方法上指定生命周期参数有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31470146/

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