代码之家  ›  专栏  ›  技术社区  ›  John M.

“特征绑定选项<字符串>:Copy`不满足”是什么意思?

  •  0
  • John M.  · 技术社区  · 5 年前

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

    #[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
    

    当我实施 Copy Clone ,一切正常:

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

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

    3. 为什么在传递 MyType 以价值衡量函数?我猜它正在被移动,所以一开始就没有拷贝。

    0 回复  |  直到 8 年前
        1
  •  24
  •   Vladimir Matveev    11 年前

    与C/C++相反,Rust在复制和移动的类型之间有非常明确的区别。请注意,这只是语义上的区别;在实施层面上采取行动 然而,作为一个浅字节复制,编译器对如何处理从中移动的变量设置了某些限制。

    默认情况下 每一个 类型仅可移动(不可复制)。这意味着这些类型的值会四处移动:

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

    你看,存储在 x 已移至 y ,所以你不能用它做任何事 十、 .

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

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

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

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

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

    (派生) Clone 因为 复制 继承 克隆 所以一切 复制 也必须是 克隆 )

    如果您的类型原则上可以自动复制,也就是说,它没有关联的析构函数,并且它的所有成员都是可复制的 复制 ,然后 得到 你的类型也是 复制 .

    你可以用 复制 在数组初始值设定项中输入正是因为数组将用该初始值设定项中使用的值的字节副本初始化,所以您的类型必须实现 复制 表明它确实 可以 可以自动复制。

    以上是1和2的答案。至于第三点,是的,你完全正确。它确实可以工作,因为值被移动到函数中。如果你试图使用 MyType 在将其传递到函数中后,您会很快注意到关于使用移动值的错误。

        2
  •  5
  •   nbro kai    8 年前

    为什么我需要指定一个空拷贝特性实现?

    Copy 是一种特殊的内在特质 T 实施 复制 表示复制类型的值是安全的 T 使用浅字节拷贝。

    这个简单的定义意味着只需要告诉编译器这些语义是正确的,因为运行时行为没有根本性的改变:都是移动(非移动)- 复制 类型)和“副本”都是浅字节副本,只是源代码以后是否可用的问题。看见 an older answer for more details .

    (如果 MyType 不是吗 复制 它本身以前它会自动实现,但现在一切都变了 with opt-in built-in traits .)

    创建数组就是通过浅拷贝复制值,如果 T 复制 .在更一般的情况下是安全的, #5244 涵盖了其中一些,但在核心,非- 复制 struct无法用于自动创建固定长度数组,因为编译器无法判断复制是否安全/正确。

    有没有更简单的方法来做这件事,或者我必须重新思考一些事情(我来自C)?

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

    将插入适当的空实现( #[derive] 与其他几个特征一起工作,例如 #[derive(Copy, Clone, PartialEq, Eq)] .)

    为什么在传递 MyType 以价值衡量函数?我猜它正在被移动,所以一开始就没有拷贝。

    嗯,如果不调用函数,就看不到移动与复制行为(如果你在同一时间调用它两次)- 复制 值时,编译器将发出有关移动值的错误)。但是,机器上的“移动”和“复制”本质上是相同的。在Rust中,值的所有按值使用都是语义上的浅拷贝,就像在C中一样。