什么实际上在 Rust 中移动变量?

What is actually moving a variable in Rust?

我从来没有尝试过 C、C++、Go 等语言,我决定从 Rust 开始,我已经了解了一些堆栈和堆是什么,但是,它到底意味着什么移动一个变量,documentation 表示它不是浅拷贝:

... probably sounds like making a shallow copy. But because Rust also invalidates the first variable, instead of calling it a shallow copy, it’s known as a move. In this example, we would say that s1 was moved into s2...

例如:

 let s1 = String::from("hello");
 let s2 = s1;

 println!("{}, world!", s1);

文档中所说的“无效”是什么意思。这是否意味着 Rust 使 s1 无效并将 s1 中的值分配给 s2,所以... s1 不存在? o 它有什么价值吗?,这主要是我不明白的,它真的会动吗?还是内存中 s1 中还有任何值?

据我所知,这个检查发生在编译时,所以这让我认为 s1 字面上不存在于内存中,只有 s2,因为 s1 从字面上移动到s2.

显然,这种情况发生在大小未知的值上,即在堆中。

希望你能帮我理解。 :)

几乎每个 yes/no 您提出的问题的答案都是肯定的和否定的。我们可以在两种不同的上下文中回答这个问题:语言的语义,以及编译器对代码的处理方式。

在语义上,s1 值移入 s2 后无法再读取。它 可以 初始化为新的 String 值,然后再次使用。从某种意义上说,“未初始化”和“已移出”实际上是相同的状态,因为您必须先为变量赋值,然后才能使用它。 (它们在编译器给出的消息中有点不同,结构的 sub-values 可以是 moved-from,但不能未初始化。)

编译器会用它做什么?好吧,这取决于很多因素,包括(但不限于)编译器的版本和选择的优化级别。如果编译器愿意,它可以 完全省略 移动,因此 s2 实际上只是与 s1 相同内存区域的另一个名称。它还可以在堆栈上为 s2 提供自己的内存区域,并将 s1 的内容写入其中。任何关于编译器做什么的具体答案都必须用编译环境、编译器版本和给编译器的标志的完整描述来限定。

Obviously this happens with values that have an unknown size, that is, in the heap.

任何拥有的(和未固定的)值都可以移动,无论它是否管理堆上的分配。通常,堆分配不会自行移动。指向堆分配的指针被移动到它的新位置。 (例如,移动 StringVec 不会改变存储实际内容的内存位置。指向该数据的指针只是易手。)

What does the documentation mean when it says "invalidates". Does this mean that Rust invalidates s1 and assigns the value that was in s1 to s2, so... s1 doesn't exist?

这意味着您作为开发人员无法再访问 s1。所以,从你的角度来看,你可以认为 s1 不存在。

Does it have any value?

不,因为它不存在(从你的角度来看)。

does it really move it?

取决于程序和编译器。从概念上讲,确实如此。

or is there still any value in s1 in memory?

即使不谈移动,一般情况下变量可能永远不会在内存中开始!这取决于优化器的作用。

this check happens at compile time

是的,它发生在编译时。

so it makes me think that s1 literally doesn't exist in memory and only s2, since s1 was literally moved to s2.

不,这取决于。两者,其中一个或none可能存在于内存,缓存,寄存器中......要知道你需要检查特定情况。