本文介绍了当外部生命周期不同时,为什么不能将一个引用的引用取消分配给另一个引用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要编写以下函数:

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).

这篇关于当外部生命周期不同时,为什么不能将一个引用的引用取消分配给另一个引用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-02 11:23