这里有一个关于Rust's move语义的很好的例子:Rust By example网站上的Rust Move Semantics.

我对这两个 case 都有基本的了解.第一个问题是,原语可以有一个新的别名,而原语仍然可以使用,因为最终的结果是一个副本,因为i32利用了Copy特征.这对我来说很有意义.

此外,出于许多好的原因,第二个示例在具有多个别名(表示堆上的i32)方面是有意义的.Rust强制执行所有权规则,因此,既然创建了新绑定,就不能使用原始别名.这有助于防止数据竞争、双重释放等.

但似乎还有第三个 case 没有被提及.How does Rust implement moves of stack allocated structs that do not implement the 100 trait?以下代码说明了这一点:

#[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);
}

我知道:在上面的例子中,Rust will allocate the 100 on the stack.上述 struct does not implement the 101 trait,因此在分配给新别名时不会被复制.这让我非常困惑,因为如果在堆栈上分配了Employee struct ,并且没有实现Copy trait,那么它在哪里/如何移动?它是否实际移动到do_something()的堆栈帧?

在解释这一难题时,任何帮助都将不胜感激.

推荐答案

它是否实际移动到do_something()的堆栈帧?

对.非Copy种类型的物理移动方式与Copy种类型的物理移动方式完全相同:使用memcpy.您已经了解了primitive Copy类型是逐字节复制到新位置(例如新堆栈帧)的.

现在考虑Box的这种实现:

struct Box<T> {
    ptr: *const T,
}

当你有

let b = Box::new(27i32);
do_something(b);    // `b` is moved into `do_something`

然后在堆上分配一个i32Box保存指向该堆分配内存的原始指针.请注意,Box Direct(内部的原始指针)直接位于堆栈上,而不是堆上!只有i32个在堆上.

Box被移动时,它是memcpy,正如我刚才所说.这意味着将复制堆栈内容(!!)...因此,指针是逐字节复制的.i32没有第二个版本!

Copy人和非Copy人在身体运动方面没有区别.唯一的区别是编译器对这些类型强制执行不同的规则.

Rust相关问答推荐

如何处理对打包字段的引用是未对齐错误?

有没有方法处理rust中嵌套的ok_or()?

将此字符串转换为由空格字符分隔的空格

如何从Rust记录WASM堆内存使用情况?

铁 rust 中的共享对象实现特征

当T不执行Copy时,如何返回Arc Mutex T后面的值?

如何在不调用Collect()的情况下为新型vec实现IntoIterator?

在Rust中,Box:ed struct 与普通 struct 在删除顺序上有区别吗?

为什么不';t(&;mut-iter).take(n)取得iter的所有权?

使用占位符获取用户输入

为什么是&mut发送?线程如何在安全的 Rust 中捕获 &mut?

Rust 1.70 中未找到 Trait 实现

相当于 Rust 中 C++ 的 std::istringstream

如何为整数切片定义一个带有额外函数的特性别名?

实现泛型的 Trait 方法中的文字

为什么传递 option.as_ref 的行为不同于使用匹配块并将内部映射到 ref 自己?

为什么 &i32 可以与 Rust 中的 &&i32 进行比较?

当我不满足特征界限时会发生什么?

在空表达式语句中移动的值

带有库+多个二进制文件的Cargo 项目,二进制文件由多个文件组成?