Rust 中的引用分配

And*_*ndy 3 rust

下面的代码不能编译,因为x在 move 之后使用(因为x有 type &mut u8,它没有实现Copytrait)

fn main() {
    let mut a: u8 = 1;
    let x: &mut u8 = &mut a;
    let y = x;
    x;
}
Run Code Online (Sandbox Code Playgroud)

据我所知,y隐式具有类型&mut u8

但是如果我明确指定y它编译的类型。以下代码编译

fn main() {
    let mut a: u8 = 1;
    let x: &mut u8 = &mut a;
    let y: &mut u8 = x;
    x;
}
Run Code Online (Sandbox Code Playgroud)

顺便说一句,如果我更改let y: &mut u8 = x;let y: &u8 = x;它还会编译。

在我看来,一切都没有改变,y&mut u8在第一个例子,它是&mut u8在第二,但前者不编译和后者则编译。

为什么?有什么不同?

HTN*_*TNW 5

&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;
    }
}
Run Code Online (Sandbox Code Playgroud)

这仍然不是完全明确的,因为y仍然不知道的类型。它是什么?好吧,由于它是从 分配的x,它是 a &'a mut u8,它也应该是 a &'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;
    }
}
Run Code Online (Sandbox Code Playgroud)

嗯,那不好。由于与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
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,不是将引用x移入y并使其无效,而是将值*x临时“重新借用”到 make y,如 by 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;
}
Run Code Online (Sandbox Code Playgroud)

原理和以前一样:说&得越频繁,编译器就有更多的地方可以按摩程序中的生命周期,使一切正常。