为什么默认(结构值)数组初始化需要 Copy trait? [英] Why is the Copy trait needed for default (struct valued) array initialization?

查看:39
本文介绍了为什么默认(结构值)数组初始化需要 Copy trait?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

When I define a struct like this, I can pass it to a function by value without adding anything specific:

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

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

当我想创建一个带有默认值的 MyType 实例数组时

When I want to create an array of MyType instances with a default value

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

Rust 编译器告诉我:

The Rust compiler tells me:

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时,一切正常:

When I implement Copy and Clone, everything works:

impl Copy for MyType {}
impl Clone for MyType {
    fn clone(&self) -> Self {
        MyType {
            member: self.member.clone(),
        }
    }
}

  1. 为什么我需要指定一个空的 Copy trait 实现?

有没有更简单的方法可以做到这一点,或者我必须重新考虑一些事情?

Is there a simpler way to do this or do I have to re-think something?

为什么将 MyType 的实例按值传递给函数时会起作用?我的猜测是它正在被移动,所以首先没有副本.

Why does it work when passing an instance of MyType to the function by value? My guess is that it is being moved, so there is no copy in the first place.

推荐答案

与 C/C++ 相反,Rust 在复制和移动类型之间有非常明确的区别.请注意,这只是语义上的区别;在实现层面上,move 一个浅的字节拷贝,但是,编译器对你可以对你从中移动的变量执行的操作施加了某些限制.

Contrary to C/C++, Rust has very explicit distinction between types which are copied and which are moved. Note that this is only a semantic distinction; on the implementation level move is a shallow bytewise copy, however, the compiler places certain restrictions on what you can do with variables you moved from.

默认情况下每种类型只能移动(不可复制).这意味着这些类型的值会四处移动:

By default every type is only moveable (non-copyable). It means that values of such types are moved around:

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

您看,存储在 x 中的值已移至 y,因此您无法对 x 执行任何操作.

You see, the value which was stored in x has been moved to y, and so you can't do anything with x.

移动语义是 Rust 中所有权概念的一个非常重要的部分.您可以在官方指南中阅读更多相关内容.

Move semantics is a very important part of ownership concept in Rust. You can read more on it in the official guide.

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

Some types, however, are simple enough so their bytewise copy is also their semantic copy: if you copy a value byte-by-byte, you will get a new completely independent value. For example, primitive numbers are such types. Such property is designated by Copy trait in Rust, i.e. if a type implements Copy, then values of this type are implicitly copyable. Copy does not contain methods; it exists solely to mark that implementing types have certain property and so it is usually called a marker trait (as well as few other traits which do similar things).

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

However, it does not work for all types. For example, structures like dynamically allocated vectors cannot be automatically copyable: if they were, the address of the allocation contained in them would be byte-copied too, and then the destructor of such vector will be run twice over the same allocation, causing this pointer to be freed twice, which is a memory error.

所以默认情况下,Rust 中的自定义类型是不可复制的.但是您可以选择使用 #[derive(Copy, Clone)](或者,如您所见,使用直接 impl;它们是等效的,但是 derive 通常读起来更好):

So by default custom types in Rust are not copyable. But you can opt-in for it using #[derive(Copy, Clone)] (or, as you noticed, using direct impl; they are equivalent, but derive usually reads better):

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

(派生Clone是必要的,因为Copy继承了Clone,所以所有Copy也必须是<代码>克隆)

(deriving Clone is necessary because Copy inherits Clone, so everything which is Copy must also be Clone)

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

If your type can be automatically copyable in principle, that is, it doesn't have an associated destructor and all of its members are Copy, then with derive your type will also be Copy.

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

You can use Copy types in array initializer precisely because the array will be initialized with bytewise copies of the value used in this initializer, so your type has to implement Copy to designate that it indeed can be automatically copied.

以上是1和2的答案.至于3,是的,你完全正确.它确实有效,因为该值已移入函数中.如果您在将 MyType 类型的变量传递给函数后尝试使用它,您会很快注意到有关使用移动值的错误.

The above was the answer to 1 and 2. As for 3, yes, you are absolutely correct. It does work precisely because the value is moved into the function. If you tried to use a variable of MyType type after you passed it into the function, you would quickly notice an error about using a moved value.

这篇关于为什么默认(结构值)数组初始化需要 Copy trait?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆