当我定义这样的 struct 时,我可以通过值将其传递给函数,而无需添加任何特定内容:

#[derive(Debug)]
struct MyType {
    member: u16,
}

fn my_function(param: MyType) {
    println!("param.member: {}", param.member);
}

当我想要创建一个包含MyType个默认值实例的数组时

fn main() {
    let array = [MyType { member: 1234 }; 100];
    println!("array[42].member: ", array[42].member);
}

Rust编译器告诉我:

error[E0277]: the trait bound `MyType: std::marker::Copy` is not satisfied
  --> src/main.rs:11:17
   |
11 |     let array = [MyType { member: 1234 }; 100];
   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `MyType`
   |
   = note: the `Copy` trait is required because the repeated element will be copied

当我实现CopyClone时,一切正常:

impl Copy for MyType {}
impl Clone for MyType {
    fn clone(&self) -> Self {
        MyType {
            member: self.member.clone(),
        }
    }
}
  1. 为什么我需要指定一个空的Copy trait实现?

  2. 有没有更简单的方法,或者我需要重新思考一下?

  3. 当通过值将MyType的实例传递给函数时,它为什么工作?我猜它正在被移动,所以一开始就没有拷贝.

推荐答案

与C/C++相反,Rust在复制和移动的类型之间有非常明确的区别.请注意,这只是语义上的区别;然而,在实现级别move is是一个浅字节拷贝,编译器对您可以使用从中移动的变量进行某些限制.

默认情况下,every type仅可移动(不可复制).这意味着这些类型的值会四处移动:

let x = SomeNonCopyableType::new();
let y = x;
x.do_something();      // error!
do_something_else(x);  // error!

你看,存储在x中的值被移动到了y,所以你不能用x做任何事情.

移动语义是Rust中所有权概念的重要组成部分.你可以阅读更多关于它的内容.

然而,有些类型足够简单,所以它们的字节复制也是它们的语义复制:如果一个字节一个字节地复制一个值,就会得到一个完全独立的新值.例如,原始数就是这样的类型.此类属性在Rust中由Copy trait指定,即如果一个类型实现了Copy,那么该类型的值是隐式可复制的.Copy不包含方法;它的存在仅仅是为了标记实现类型具有特定的属性,因此它通常被称为标记特征(以及其他一些做类似事情的特征).

然而,它并不适用于所有类型.例如,像动态分配的向量这样的 struct 不能自动复制:如果是,则其中包含的分配地址也将被字节复制,然后此类向量的析构函数将在同一分配上运行两次,导致该指针被释放两次,这是一个内存错误.

因此,默认情况下,Rust中的自定义类型是不可复制的.但你可以 Select #[derive(Copy, Clone)](或者,正如你所注意到的,使用direct impl;它们是等效的,但derive通常读起来更好):

#[derive(Copy, Clone)]
struct MyType {
    member: u16
}

(推导Clone是必要的,因为Copy继承了Clone,所以所有Copy也必须是Clone)

如果您的类型原则上可以自动复制,也就是说,它没有关联的析构函数,并且它的所有成员都是Copy,那么使用derive,您的类型也将是Copy.

您可以在数组初始值设定项中使用Copy个类型,因为数组将使用该初始值设定项中使用的值的字节副本进行初始化,所以您的类型必须实现Copy,以指定它将被自动复制.

以上是1和2的答案.至于第三点,是的,你完全正确.它确实可以工作,因为值被移动到函数中.如果在将MyType类型的变量传递到函数后try 使用该变量,则会很快注意到有关使用移动值的错误.

Rust相关问答推荐

重新导出proc宏导致未解决的extern crate错误""

铁 rust 干线无法使用PowerShell获取环境变量

为什么我可以跟踪以前borrow 过的变量?房主在哪里?

有没有办法在Rust中配置常量变量的值?

当对VEC;U8>;使用serde_json时,Base64编码是保护空间的好方法吗?

我可以在不收集或克隆的情况下,将一个带有Item=(key,val)的迭代器拆分成单独的key iter和val iter吗?

如何使用RefCell::JOYMOMTborrow 对 struct 不同字段的可变引用

借来的价值生命周期 不够长,不确定为什么它仍然是借来的

在描述棋盘时如何最好地使用特征与枚举

max(ctz(x), ctz(y)) 有更快的算法吗?

push 方法是否取得所有权?

为什么 for_each 在释放模式(cargo run -r)下比 for 循环快得多?

为什么 File::read_to_end 缓冲区容量越大越慢?

切片不能被 `usize` 索引?

如何获取函数中borrow 的切片的第一部分?

第 7.4 章片段中如何定义 `thread_rng`

使用方法、关联函数和自由函数在 Rust 中初始化函数指针之间的区别

字符串切片的向量超出范围但原始字符串仍然存在,为什么判断器说有错误?

Rust 跨同一文件夹中文件的可见性

为什么 std::iter::Peekable::peek 可变地borrow self 参数?