当外部生命周期不同时,为什么不能将一个引用的引用取消分配给另一个引用?

问题描述 投票:3回答:1

我想编写以下功能:

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的引用到寿命为'cu32的引用”。因此,当我取消引用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对行为的正确解释是什么?为何引用的引用以这种方式而不是我以为的方式运行?

rust lifetime
1个回答
7
投票

您不能取消引用&'b mut &'c mut u32并获得&'c mut u32,因为:

  • &mut引用不是很容易复制,因此您不能copy &'c mut u32;和
  • 您不能移出参考,因此也不能移动 &'c mut u32(这会使外部参考悬空)。

相反,编译器重新借用具有外部生存期u32'b。这就是为什么您会收到一条错误消息,说明来自rr2的数据流入rr1

如果允许编译foo,则可以使用它来获取对同一&mut的两个u32引用,这是引用规则所禁止的:

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!

如果我要求'b胜过'c,则可以使用

因为'c必须已经超过'b,所以如果您要求'b也超过'c,则得出'c = 'b。更新的签名等效于此:

fn foo<'a, 'b>(rr1: &'a mut &'b mut u32, rr2: &'b mut &'b mut u32)

也就是说,您已经统一了'c'b,现在从&'b mut u32借用rr2毫无问题,因为内部和外部生命周期都适用于'b。但是,编译器现在不允许您在我之前给出的示例中编写损坏的代码,因为ry已在整个生命周期中被借用。

有趣的是,如果将内部引用设为非mut,它也可以工作:

fn foo<'a, 'b, 'c>(rr1: &'a mut &'c u32, rr2: &'b mut &'c u32) {
    *rr1 = *rr2;
}

这是因为&引用是Copy,所以*rr2不是重新借用,而实际上只是内部值的副本。有关更多信息,请阅读Why does linking lifetimes matter only with mutable references?

© www.soinside.com 2019 - 2024. All rights reserved.