当外部生命周期不同时,为什么我不能将引用的引用的一个解引用分配给另一个引用?
Why can't I assign one dereference of a reference of a reference to another when the outer lifetimes differ?
我想编写如下函数:
fn foo<'a, 'b, 'c>(rr1: &'a mut &'c mut u32, rr2: &'b mut &'c mut u32) {
*rr1 = *rr2;
}
但是编译器抱怨:
error[E0623]: lifetime mismatch
--> src/lib.rs:2:12
|
1 | fn foo<'a, 'b, 'c>(rr1: &'a mut &'c mut u32, rr2: &'b mut &'c mut u32) {
| ----------- ------------------- these two types are declared with different lifetimes...
2 | *rr1 = *rr2;
| ^^^^ ...but data from `rr2` flows into `rr1` here
我对 Rust 生命周期的心智模型不同意代码是错误的。我读 rr2
的类型为 "A reference with lifetime 'b
to a reference with lifetime 'c
to an u32
"。因此,当我取消引用 rr2
时,我得到了一个生命周期为 'c
的 u32
引用。这应该可以安全地存储在具有相同类型的 *rr1
中。
如果我要求 'b
比 'c
长,它会起作用:
fn foo<'a, 'b: 'c, 'c>(rr1: &'a mut &'c mut u32, rr2: &'b mut &'c mut u32) {
*rr1 = *rr2;
}
这让我觉得类型&'b mut &'c mut u32
意味着引用链末尾的u32
仅在'b
和'c
交集期间可用。
这里对 Rust 行为的正确解释是什么?为什么引用的引用会这样而不是我认为的那样?
您不能取消引用 &'b mut &'c mut u32
并获得 &'c mut u32
,因为:
&mut
引用不是简单可复制的,所以你不能 copy &'c mut u32
;和
- 您不能移出引用,因此您也不能移动
&'c mut u32
(这会使外部引用悬空)。
相反,编译器 重新借用 具有外部生命周期 'b
的 u32
。这就是为什么您会收到一条错误消息,指出来自 rr2
的数据流入 rr1
.
如果 foo
被允许编译,您可以使用它来获得对同一个 u32
的两个 &mut
引用,这是引用规则所禁止的:
let (mut x, mut y) = (10, 20);
let mut rx = &mut x;
let mut ry = &mut y;
foo(&mut rx, &mut ry); // rx and ry now both refer to y
std::mem::swap(rx, ry); // undefined behavior!
If I require that 'b outlives 'c, it works
因为 'c
必须比 'b
¹ 长寿,如果您要求 'b
也比 'c
长寿,那么 'c
= 'b
.更新后的签名等同于:
fn foo<'a, 'b>(rr1: &'a mut &'b mut u32, rr2: &'b mut &'b mut u32)
也就是你统一了'c
和'b
,现在从rr2
借一个&'b mut u32
就没有问题了,因为内生和外生都活了'b
。但是,编译器现在不允许您编写我之前给出的示例中的损坏代码,因为 ry
已经被借用了整个生命周期。
有趣的是,如果你使内部引用非mut
,它也有效:
fn foo<'a, 'b, 'c>(rr1: &'a mut &'c u32, rr2: &'b mut &'c u32) {
*rr1 = *rr2;
}
这是因为&
引用是Copy
,所以*rr2
不是借用,实际上只是内部值的拷贝。
有关详细信息,请阅读:
¹ 当没有明确的 'c: 'b
绑定时,为什么 'c
比 'b
长寿可能并不明显。原因是因为编译器假定类型 &'b mut &'c mut u32
是 良构的 。良构性可能会变得复杂(参见 RFC 1214),但在这种情况下,它仅意味着您不能拥有比它所引用的事物('c
)有效期更长('b
)的引用).
我想编写如下函数:
fn foo<'a, 'b, 'c>(rr1: &'a mut &'c mut u32, rr2: &'b mut &'c mut u32) {
*rr1 = *rr2;
}
但是编译器抱怨:
error[E0623]: lifetime mismatch
--> src/lib.rs:2:12
|
1 | fn foo<'a, 'b, 'c>(rr1: &'a mut &'c mut u32, rr2: &'b mut &'c mut u32) {
| ----------- ------------------- these two types are declared with different lifetimes...
2 | *rr1 = *rr2;
| ^^^^ ...but data from `rr2` flows into `rr1` here
我对 Rust 生命周期的心智模型不同意代码是错误的。我读 rr2
的类型为 "A reference with lifetime 'b
to a reference with lifetime 'c
to an u32
"。因此,当我取消引用 rr2
时,我得到了一个生命周期为 'c
的 u32
引用。这应该可以安全地存储在具有相同类型的 *rr1
中。
如果我要求 'b
比 'c
长,它会起作用:
fn foo<'a, 'b: 'c, 'c>(rr1: &'a mut &'c mut u32, rr2: &'b mut &'c mut u32) {
*rr1 = *rr2;
}
这让我觉得类型&'b mut &'c mut u32
意味着引用链末尾的u32
仅在'b
和'c
交集期间可用。
这里对 Rust 行为的正确解释是什么?为什么引用的引用会这样而不是我认为的那样?
您不能取消引用 &'b mut &'c mut u32
并获得 &'c mut u32
,因为:
&mut
引用不是简单可复制的,所以你不能 copy&'c mut u32
;和- 您不能移出引用,因此您也不能移动
&'c mut u32
(这会使外部引用悬空)。
相反,编译器 重新借用 具有外部生命周期 'b
的 u32
。这就是为什么您会收到一条错误消息,指出来自 rr2
的数据流入 rr1
.
如果 foo
被允许编译,您可以使用它来获得对同一个 u32
的两个 &mut
引用,这是引用规则所禁止的:
let (mut x, mut y) = (10, 20);
let mut rx = &mut x;
let mut ry = &mut y;
foo(&mut rx, &mut ry); // rx and ry now both refer to y
std::mem::swap(rx, ry); // undefined behavior!
If I require that 'b outlives 'c, it works
因为 'c
必须比 'b
¹ 长寿,如果您要求 'b
也比 'c
长寿,那么 'c
= 'b
.更新后的签名等同于:
fn foo<'a, 'b>(rr1: &'a mut &'b mut u32, rr2: &'b mut &'b mut u32)
也就是你统一了'c
和'b
,现在从rr2
借一个&'b mut u32
就没有问题了,因为内生和外生都活了'b
。但是,编译器现在不允许您编写我之前给出的示例中的损坏代码,因为 ry
已经被借用了整个生命周期。
有趣的是,如果你使内部引用非mut
,它也有效:
fn foo<'a, 'b, 'c>(rr1: &'a mut &'c u32, rr2: &'b mut &'c u32) {
*rr1 = *rr2;
}
这是因为&
引用是Copy
,所以*rr2
不是借用,实际上只是内部值的拷贝。
有关详细信息,请阅读:
¹ 当没有明确的 'c: 'b
绑定时,为什么 'c
比 'b
长寿可能并不明显。原因是因为编译器假定类型 &'b mut &'c mut u32
是 良构的 。良构性可能会变得复杂(参见 RFC 1214),但在这种情况下,它仅意味着您不能拥有比它所引用的事物('c
)有效期更长('b
)的引用).