Rust中引用的赋值方式

6
以下代码无法编译,因为move之后使用了x(由于x的类型为&mut u8,它没有实现Copy trait)。
fn main() {
    let mut a: u8 = 1;
    let x: &mut u8 = &mut a;
    let y = x;
    x;
}

据我了解,y 隐式地具有类型 &mut u8

但是如果我显式指定y的类型,它将会编译。以下代码可以编译:

fn main() {
    let mut a: u8 = 1;
    let x: &mut u8 = &mut a;
    let y: &mut u8 = x;
    x;
}

顺便提一下,如果我把 let y: &mut u8 = x; 改成 let y: &u8 = x;,它仍会编译通过。
对我来说,似乎没有什么改变,y 在第一个示例中是 &mut u8,在第二个示例中也是 &mut u8,但前者不能编译通过,而后者可以编译通过。
为什么?有什么区别?

“根据我的理解,y 隐式地具有 &mut u8 类型。”我目前没有 IDE 在面前,但我认为这是错误的,y 的类型应该是 &u8 - Hristo Kolev
let y: &u8 = x; 也可以编译通过。 - Andy
我当时错了。你能给我错误信息吗? - Hristo Kolev
error[E0382]: use of moved value: x`` - Andy
链接到 Rust Playground: link - Andy
我认为这里发生了重新借用;也就是说,以某种方式指定y的类型会改变x被移动到重新借用x(寿命更短),因此由于y未被使用,重新借用立即结束,x再次可用。然而,我不知道原因是什么... - Matthieu M.
1个回答

6

&mut u8 不是一个完整的类型。所有引用类型都必须在它们上面有生命周期参数。当你省略它时,Rust编译器必须推断它,并且它将选择最短的生命周期。在你的第一个例子中,展开的第一步是(使用Rustonomicon中的伪语法):

fn main() {
    let mut a: u8 = 1;
    'a: {
    let x: &'a mut u8 = &'a mut a; // the lifetime of x must last until it's use at the end
    let y = x;
    x;
    }
}

这仍然不是完全明确的,因为y的类型仍然未知。那它是什么呢?嗯,由于它是从x分配而来的,而x是一个&'a mut u8,所以它也应该是一个&'a mut u8。请注意,这并不遵循生命期省略的“尽可能缩短生命周期”的规则。您没有省略生命周期,而是省略了整个类型,这个类型是通过类型推断重新构建的。

fn main() {
    let mut a: u8 = 1;
    'a: {
    let x: &'a mut u8 = &'a mut a; // the lifetime of x must last until its use at the end
    let y: &'a mut u8 = x;
    x;
    }
}

好的,这不太好。由于y的生命周期与x相同,因此创建它涉及将x中的引用移动并使x无效。 因此,程序因尝试使用x而被拒绝。

y添加签名基本上为编译器提供了一个可以推断生命周期的新位置。 在此之前,正常类型推断使y具有与x相同的类型,这意味着它与x的寿命相同,并使x不可用。 现在,y不需要与x具有相同的类型;借用的生命周期可以不同。 特别是,它变得更短。

fn main() {
    let mut a: u8 = 1;
    'a: {
    let x: &'a mut u8 = &'a mut a; // the lifetime of x must last until it's use at the end
    'b: {
    let y: &'b mut u8 = x; // y and x can now have different lifetimes, *x is reborrowed here
    }
    x; // x not moved from, still valid
    }
}

现在,不再将引用x移入y并使其无效,而是暂时“重新借用”*x来生成y,如使用let y: &'b mut u8 = &'b mut *x

另一种可能的修复方法是明确地说“使用不同的生命周期再次借用*x”:

fn main() {
    let mut a: u8 = 1;
    let x: &mut u8 = &mut a;
    let y = &mut *x;
    x;
}

原则与之前相同:更频繁地使用 & 让编译器有更多的空间来调整程序中的生命周期以使所有东西都能正常工作。

谢谢你的回答!你能否简要回答一下,这里我们不是同时有两个可变引用 a 吗?这也可以用生命周期来解释吗?所以我们有一个借用者 x,然后只有一个借用者 y,然后又是 x - Andy
我不认为这可以用生命周期来解释。借用检查器跟踪ax借用,然后被y借用,然后再次被x借用,但我不认为这实际上写入了生命周期中。不过我也不确定。 - HTNW

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接