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

Lor*_*enz 5 lifetime rust

我想编写以下函数:

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

但是编译器抱怨:

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

我对 Rust 生命周期的心智模型不同意代码是错误的。我读的类型rr2为“具有寿命的引用'b与寿命的参考'c到一个u32”。因此,当我提领rr2,我与寿命引用'cu32。这应该可以安全地存储在*rr1具有相同类型的 中。

如果我需要它的'b寿命'c,它的工作原理:

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

这使我认为该类型&'b mut &'c mut u32u32的交叉点期间,在参考链的末端是唯一可用的'b'c

对 Rust 在这里的行为的正确解释是什么?为什么引用的引用会以这种方式而不是我认为的方式?

tre*_*tcl 9

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

  • &mut引用是不可复制的,所以你不能复制&'c mut u32; 和
  • 你不能搬出参考的,所以你也可以不移动&'c mut u32(这会使外参考悬挂)。

相反,编译器reborrowsu32与外寿命'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!
Run Code Online (Sandbox Code Playgroud)

如果我要求 'b 比 'c 长,它就可以工作

因为'c必须已经超过'b¹,如果你要求它'b也超过'c,那么'c= 'b。更新后的签名相当于:

fn foo<'a, 'b>(rr1: &'a mut &'b mut u32, rr2: &'b mut &'b mut u32)
Run Code Online (Sandbox Code Playgroud)

也就是说,您已经统一了'cand 'b,现在借用 a &'b mut u32from没有问题,rr2因为内部和外部生命周期都为'b. 但是,编译器现在不会让您在我之前给出的示例中编写损坏的代码,因为ry它的整个生命周期都已被借用。

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

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

这是因为&引用是Copy,所以*rr2不是重新借用,而实际上只是内部值的副本。

有关更多信息,请阅读:


¹当没有明确的界限时,为什么会'c长寿可能并不明显。原因是因为编译器假定类型是well-formed。格式良好可能会变得复杂(请参阅RFC 1214),但在这种情况下,它仅意味着您不能拥有比它所引用的事物()更有效的引用()。'b'c: 'b&'b mut &'c mut u32'b'c