几天前,有人a question有人对链接的生命周期有一个问题,这个生命周期是一个包含借来的数据本身的类型的可变引用。问题是提供对类型的引用,借用与类型内部借用数据相同的生命周期。 我试图重新创建问题:
struct VecRef<'a>(&'a Vec<u8>);
struct VecRefRef<'a>(&'a mut VecRef<'a>);
fn main() {
let v = vec![8u8, 9, 10];
let mut ref_v = VecRef(&v);
create(&mut ref_v);
}
fn create<'b, 'a>(r: &'b mut VecRef<'a>) {
VecRefRef(r);
}
我在'b
中明确注释create()
。这不编译:
error[E0623]: lifetime mismatch
--> src/main.rs:12:15
|
11 | fn create<'b, 'a>(r: &'b mut VecRef<'a>) {
| ------------------
| |
| these two types are declared with different lifetimes...
12 | VecRefRef(r);
| ^ ...but data from `r` flows into `r` here
生命周期'b
类似于'b < 'a
,因此违反了VecRefRef<'a>
中的约束,其生命周期与引用的VecRef<'a>
完全相同。
我将可变引用的生命周期与VecRef<'a>
:
fn create<'a>(r: &'a mut VecRef<'a>) {
VecRefRef(r);
}
现在它有效。但为什么?我怎么能提供这样的参考? r
内的可变引用create()
的生命周期为VecRef<'a>
而不是'a
。为什么问题没有推到函数create()
的调用端?
我注意到另一件我不理解的事情。如果我在VecRefRef<'a>
结构中使用 immutable 引用,那么在提供具有不同生命周期'a
的引用时,它会以某种方式无关紧要:
struct VecRef<'a>(&'a Vec<u8>);
struct VecRefRef<'a>(&'a VecRef<'a>); // now an immutable reference
fn main() {
let v = vec![8u8, 9, 10];
let mut ref_v = VecRef(&v);
create(&mut ref_v);
}
fn create<'b, 'a>(r: &'b mut VecRef<'a>) {
VecRefRef(r);
}
这与VecRefRef<'a>
对VecRef<'a>
的可变引用的第一个示例相反。我知道可变引用具有不同的别名规则(根本没有别名)但是这与链接的生命周期有什么关系呢?
答案 0 :(得分:5)
r
内的可变引用create()
的有效期为VecRef<'a>
而非'a
这是混淆的常见原因。检查此功能定义:
fn identity<'a, T>(val: &'a T) -> &'a T { val }
在函数定义中,'a
是泛型生命周期参数,它与泛型类型参数(T
)平行。调用该函数时,调用者将决定'a
和T
的具体值。让我们回顾一下你的main
:
fn main() {
let v = vec![8u8, 9, 10]; // 1 |-lifetime of `v`
let mut ref_v = VecRef(&v); // 2 | |-lifetime of `ref_v`
create(&mut ref_v); // 3 | |
}
v
将在main
(1-3)的整个过程中生效,但ref_v
仅适用于最后两个陈述(2-3)。请注意,ref_v
指的是超过它的值。如果你接着引用ref_v
,你就可以参考(2-3)中存在的东西,它本身就是对(1-3)中存在的东西的引用。
查看您的固定方法:
fn create<'a>(r: &'a mut VecRef<'a>)
这表示用于此函数调用,对VecRef
的引用及其包含的引用必须相同。有一个生命周期可以满足这个 - (2-3)。
请注意,您的结构定义目前要求两个生命周期相同。你可以让它们有所不同:
struct VecRefRef<'a, 'b: 'a>(&'a mut VecRef<'b>);
fn create<'a, 'b>(r: &'a mut VecRef<'b>)
请注意,您必须使用语法'b: 'a
来表示生命周期'b
将超过'a
。
如果我使用不可变引用[...],那么它就不再重要了
我不太确定。我相信正在发生的事情是因为你有一个不可变借用,编译器可以自动在较小的范围内重新借用。这样可以使生命周期匹配。正如您所指出的,可变引用不能包含任何别名,即使是具有较小范围的别名,因此在这种情况下编译器也无法提供帮助。