可变借用所有权的移动

5
我理解可变借用人可以将所有权移交给另一个可变借用人。但是,这种移动似乎与移动非指针变量有所不同。让我们看一个例子。当第一次调用compute()时,p1被移动到p2。但是,在compute()返回后,所有权似乎又回到了p1
fn compute(p2: &mut Point) {
}

fn reset(p1: &mut Point) {
    compute(p1); //OK
    compute(p1); //OK
}

这与常规变量的移动方式不同。
fn compute(p2:  Point) {
}

fn reset(p1: Point) {
    compute(p1); //OK
    compute(p1); //Compile error
}

现在,在第一次 compute() 调用返回后,所有权 不会 回到 p1

这两种行为出于许多原因都是可以理解和期望的。但我只是想确认我的理解:这两个操作的性质略有不同,我这样想对吗?


可变借用者可以将所有权转移给另一个可变借用者。在我看来,你要么拥有一个对象,要么借用一个对象,没有“借用所有权”的概念。 - Shepmaster
1
@Shepmaster,引用是常规值,它们也受所有权规则的约束。如果没有重新借用,&mut 的行为将与其他不可复制的类型完全相同(即它们只能被移动)。 - Vladimir Matveev
3个回答

2
我理解的是,你的第一段代码使用了借用,而第二段则转移了所有权。
fn compute(p2:  Point) {
    // compute owns p2
} // owned p2 is freed

fn reset(p1: Point) {
    // reset() owns p1
    compute(p1); //Ownership of p1 is transferred to compute()
    compute(p1); //ERROR: p1 has already been freed
}

Vice...

fn compute(p2:  &Point) {
    // compute is borrowing p2
} // borrowed p2 is given back to owner

fn reset(p1: Point) {
    // reset() owns p1
    compute(&p1); //let compute() borrow p1, then get it back
    compute(&p1); //let compute() re-borrow p1, then give it back
} // owned p1 is freed

它们都将转移所有权,因为可变指针是不可复制的类型。然而,在 compute() 函数返回后,"reborrow" 会发生在可变指针上,使指针变量再次可用。这是我的理解。看到更正式的解释会很好。 - RajV

2

您说得没错,但是在第一种情况下,引用并没有被移动,而只是被重新借用了,这是引用特有的行为。也许这样能澄清问题,因为这不是移动语义中的异常,而是完全不同的行为。


0

另外两个答案是正确的,但我想强调 Rust 中的两个重要点:

  • 第一点是关于 Rust 中的 默认行为:当你将一个非引用对象传递给函数时,它会被移动到函数中(默认情况下!)。也就是说,函数拥有该对象的所有权,调用者在函数返回后不能再使用该对象。这就是你的第二个示例中发生的情况——因为第一次调用 compute 时获取了参数的所有权,所以在下一次调用 compute 时无法再传递相同的对象,因为它已经被移动了。

  • 如果你不想使用默认行为,那么你必须 显式地 告诉编译器你想要什么,即通过指定要传递给函数的副本(非引用对象)。对于简单的情况,这很容易——只需为你的结构体派生 CloneCopy

    #[derive(Clone, Copy)]  # 编译器的指令!
    struct Point {
        x: i32,
        y: i32,
    }
    

    如果你像这样定义你的 Point,那么即使是你的第二段代码也可以正常编译。在 playground 中看看它是如何工作的。我想 this 就是你定义 Point 的方式。


当您将任何类型作为函数参数传递时,它会被移动,包括引用。它可能是被移动的副本。 - Shepmaster
1
@Shepmaster:我们也可以采用这种思路。但我想这会使措辞略微复杂,因为在这种情况下,我必须添加“当移动的是引用时,被引用的对象不会移动”的说明。 - Nawaz

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