rust 为什么允许重新分配String而不允许 *&String

piv4azn7  于 2023-03-30  发布在  其他
关注(0)|答案(2)|浏览(146)

我知道String没有实现Copy trait。所以它不能被移动。但是我不明白下面的区别,

let greeting = String::from("Hello");
let temp = greeting; // This succeeds.

let greeting1 = String::from("Hello");
let temp1 = *&greeting1; // This fails to compile saying cannot move.

它们之间的区别是什么?为什么一个有效而另一个无效?

but5z9lq

but5z9lq1#

我知道String没有实现Copy的trait,所以它不能被移动。
这并不是真正正确的-所有类型的值都可以移动,但你需要是所有者才能移动某些东西。例如,如果你编写了一个返回类型为String的函数,当你从这个函数返回一个值时,你正在移动它(到调用者)。
Copy与此相关,因为实现Copy的类型允许您隐式地将共享引用转换为拥有的副本,然后允许您移动(因为您拥有它)。
它们之间的区别是什么?为什么一个有效而另一个无效?
&greeting1创建对字符串的共享引用;String的值不属于引用。所以*&greeting1是一个String类型的值,你不拥有它,你不允许对它做任何需要所有权的事情。

7ivaypg9

7ivaypg92#

你不能移出引用,即使你可以,你也肯定不能移出一个 shared 引用,因为移动是一个变异操作。所以你应该测试的代码是let temp1 = *&mut greeting1;,但这也不起作用。
不支持移出引用,因为移出需要编译器能够静态地确定移出位置不再被使用,并且当引用在起作用时,移出位置是未知的--引用混淆了这一点。
考虑:

fn foo(s: &mut String) {
    let x = *s;
}

fn bar() -> String {
    let s = String::new();
    foo(&mut s);
    s // What happens here?
}

bar()如何知道foo()将窃取s的值?它不可能知道这一点。当它试图在移动s后使用s时,将出现未定义的行为。
为了防止这种情况发生,只有值的所有者才能移动它。因此禁止移出参考。
请注意,您可以 “窃取”可变引用后面的值,但前提是您必须在其位置上留下一些东西。例如,内置的std::mem::take()函数将窃取可变引用后面的值, 但 * 它要求被窃取的值的类型实现Default,并且它将类型的默认值留在其位置上。这样,你可以将值移出引用,* 并且 * referent仍然是一个有效值。
在您的代码中,如下所示:

let temp1 = std::mem::take(&mut greeting1);

在这一行之后,temp1将包含用于包含的值greeting1,而greeting1将被设置为<String as Default>::default()(这将是一个空字符串)。

相关问题