Ral*_*veo 14 ownership-semantics move-semantics rust
这里记录了Rust的移动语义的一个很好的例子:在Rust By Example网站上的Rust Move Semantics.
我对两个案例都有基本的了解.第一个是原语如何具有新别名,原始仍然可以使用,因为最终结果是看到i32利用Copy特征的副本.这对我来说很有意义.
此外,由于许多好的理由,第二个示例在具有多个引用i32堆上的别名方面是有意义的.Rust强制执行所有权规则,因此现在无法使用原始别名创建新绑定.这有助于防止数据争用,双重释放等.
但似乎还有第三个案例没有被谈到.Rust如何实现不实现Copy特征的堆栈分配结构的移动? 使用以下代码对此进行说明:
#[derive(Debug)]
struct Employee{
age: i32,
}
fn do_something(m: Employee){
println!("{:?}", m);
}
fn main() {
let x = Employee {
age: 25,
};
do_something(x);
//compiler error below because x has moved
do_something(x);
}
Run Code Online (Sandbox Code Playgroud)
我知道:在上面的例子中,Rust会Employee在堆栈上分配.上述结构不实现Copy特征,因此在分配给新别名时不会被复制.这对我来说非常混乱,因为如果Employee结构被分配在堆栈上并且也没有实现Copy特性在哪里/如何移动?它是否在物理上移动到do_something()堆栈框架?
在解释这个难题时,我们对任何帮助表示赞赏.
它是否在物理上移动到
do_something()堆栈框架?
是.非Copy类型的物理移动与Copy类型完全相同:使用a memcpy.您已经了解原始Copy类型将逐字节地复制到新位置(例如,新的堆栈帧).
现在考虑这个实现Box:
struct Box<T> {
ptr: *const T,
}
Run Code Online (Sandbox Code Playgroud)
当你有
let b = Box::new(27i32);
do_something(b); // `b` is moved into `do_something`
Run Code Online (Sandbox Code Playgroud)
然后i32在堆上分配一个Box并将原始指针保存到该堆分配的内存中.请注意,Box直接(内部的原始指针)直接在堆栈上,而不是在堆上!只是i32在堆上.
正如我刚才所说Box,当它被移动时,就会被memcpy编辑.这意味着堆栈内容被复制(!!)...因此只需逐个字节地复制指针.没有第二个版本了i32!
在物理移动方面,Copy与非Copy类型之间没有区别.唯一的区别是编译器对这些类型强制执行不同的规则.