问题描述
我要编写以下函数:
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
的类型读为对生存期'b
的引用,对对生存期'c
的引用,对 u32 代码>".因此,当我取消引用
rr2
时,我得到了一个具有生存期'c
的引用到 u32
的引用.应该可以安全地存储在具有相同类型的 * rr1
中.
My mental model of Rust's lifetimes does not agree that the code is wrong. I read the type of rr2
as "A reference with lifetime 'b
to a reference with lifetime 'c
to an u32
". Thus when I dereference rr2
, I get a reference with lifetime 'c
to an u32
. This should be safe to store in *rr1
, which has the same type.
如果我要求 'b
比 'c
更有效,它就可以:
If I require that 'b
outlives 'c
, it works:
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
的交集.
This makes me think that the type &'b mut &'c mut u32
means the u32
at the end of the reference chain is only available during the intersection of 'b
and 'c
.
这里对Rust行为的正确解释是什么?为什么引用的引用会以这种方式而不是我以为的方式运行?
What is the right explanation for Rust's behavior here? And why do references of references behave this way instead of the way I thought they do?
推荐答案
您不能取消引用&'b mut&'c mut u32
并获取&'c mutu32
因为:
You cannot dereference a &'b mut &'c mut u32
and get a &'c mut u32
because:
-
& mut
引用不是很容易复制,因此您不能复制&'c mut u32
;和 - 您不能移出参考,因此也不能移动
&'c mut u32
(这会使外部参考悬空).
&mut
references are not trivially copiable, so you can't copy the&'c mut u32
; and- You cannot move out of a reference, so you also can't move the
&'c mut u32
(which would leave the outer reference dangling).
相反,编译器使用外部生存期'b
重新借用 u32
.这就是为什么您会收到一条错误消息,说明错误消息是 rr2
中的数据流入 rr1
.
Instead, the compiler reborrows the u32
with the outer lifetime, 'b
. This is why you get an error message that data from rr2
flows into rr1
.
如果允许 foo
进行编译,则可以使用它来获取对同一 u32
的两个& mut
引用,这是禁止的根据参考规则:
If foo
were allowed to compile, you could use it to get two &mut
references to the same u32
, which is forbidden by the rules of references:
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!
因为'c
必须已经超过了'b
¹,所以如果您要求'b
也要超过'c
,然后得出'c
= 'b
.更新的签名等效于此:
Because 'c
must already outlive 'b
¹, if you require that 'b
also outlives 'c
, it follows that 'c
= 'b
. The updated signature is equivalent to this:
fn foo<'a, 'b>(rr1: &'a mut &'b mut u32, rr2: &'b mut &'b mut u32)
也就是说,您已经统一了'c
和'b
,现在从那里借用&'b mut u32
没问题 rr2
是因为内寿命和外寿命均在'b
中有效.但是,编译器现在不会让您编写我之前给出的示例中损坏的代码,因为 ry
已经在其整个生命周期中被借用了.
That is, you have unified 'c
and 'b
, and now there's no problem borrowing a &'b mut u32
from rr2
because the inner and outer lifetimes both live for 'b
. However, the compiler now won't let you write the broken code in the example I gave earlier, since ry
is already borrowed for its entire lifetime.
有趣的是,如果您将内部引用设为非 mut
,则它也可以工作:
Interestingly, if you make the inner reference non-mut
, it also works:
fn foo<'a, 'b, 'c>(rr1: &'a mut &'c u32, rr2: &'b mut &'c u32) {
*rr1 = *rr2;
}
这是因为&
引用是 Copy
,所以 * rr2
不是重新借用,而实际上只是内部值的副本.
This is because &
references are Copy
, so *rr2
is not a reborrow, but actually just a copy of the inner value.
有关更多信息,请阅读:
For more information, read:
¹当没有明确的'c:'b
绑定时,为什么'c
会比'b
长寿,这可能并不明显.原因是因为编译器假定&'b mut&'c mut u32
类型是格式正确的.格式正确会变得很复杂(请参阅 RFC 1214 ),但在这种情况下,这仅意味着您不能拥有比其引用的内容('c
)更长的有效引用('b
).
¹ It might not be obvious why 'c
outlives 'b
when there is no explicit 'c: 'b
bound. The reason is because the compiler assumes that the type &'b mut &'c mut u32
is well-formed. Well-formedness can become complex (see RFC 1214) but in this case it just means you can't have a reference that's valid for longer ('b
) than the thing it references ('c
).
这篇关于当外部生命周期不同时,为什么不能将一个引用的引用取消分配给另一个引用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!