我知道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.
它们之间的区别是什么?为什么一个有效而另一个无效?
2条答案
按热度按时间but5z9lq1#
我知道
String
没有实现Copy
的trait,所以它不能被移动。这并不是真正正确的-所有类型的值都可以移动,但你需要是所有者才能移动某些东西。例如,如果你编写了一个返回类型为
String
的函数,当你从这个函数返回一个值时,你正在移动它(到调用者)。Copy
与此相关,因为实现Copy
的类型允许您隐式地将共享引用转换为拥有的副本,然后允许您移动(因为您拥有它)。它们之间的区别是什么?为什么一个有效而另一个无效?
&greeting1
创建对字符串的共享引用;String
的值不属于引用。所以*&greeting1
是一个String
类型的值,你不拥有它,你不允许对它做任何需要所有权的事情。7ivaypg92#
你不能移出引用,即使你可以,你也肯定不能移出一个 shared 引用,因为移动是一个变异操作。所以你应该测试的代码是
let temp1 = *&mut greeting1;
,但这也不起作用。不支持移出引用,因为移出需要编译器能够静态地确定移出位置不再被使用,并且当引用在起作用时,移出位置是未知的--引用混淆了这一点。
考虑:
bar()
如何知道foo()
将窃取s
的值?它不可能知道这一点。当它试图在移动s
后使用s
时,将出现未定义的行为。为了防止这种情况发生,只有值的所有者才能移动它。因此禁止移出参考。
请注意,您可以 “窃取”可变引用后面的值,但前提是您必须在其位置上留下一些东西。例如,内置的
std::mem::take()
函数将窃取可变引用后面的值, 但 * 它要求被窃取的值的类型实现Default
,并且它将类型的默认值留在其位置上。这样,你可以将值移出引用,* 并且 * referent仍然是一个有效值。在您的代码中,如下所示:
在这一行之后,
temp1
将包含用于包含的值greeting1
,而greeting1
将被设置为<String as Default>::default()
(这将是一个空字符串)。