Skip to content

Latest commit

 

History

History
75 lines (58 loc) · 3.1 KB

1.about-copy-trait.md

File metadata and controls

75 lines (58 loc) · 3.1 KB

Rust 学习之 Copy trait

最近因为疫情问题,2020 年到了2月下旬才开始复工。上班在地铁上又恢复了以往的看“微信读书”的习惯。依旧还是啃着去年没有啃完的《深入浅出Rust》。

读到“第二部分”的第11章 —— 所有权和移动语义。提到 Rust 中 move 语义是默认的,用一段代码直观的看一下:

#[derive(Debug)]
struct Point {
    x_value: i32,
    y_value: i32,
}

pub fn no_copy() {
    let v1 = Point {x_value: 1, y_value: 2};
    let v2 = v1;
    println!("{:?}", v1);
}

当我们用 cargo run 执行代码时,编译器会提示:

borrow of moved value: `v1`

也就是执行 let v2 = v1; 语句时,会将 v1 的所有权转移给 v2。之后,v1 就会被 drop 掉。

呐,这就是前面所提到的「Rust 中 move 语义是默认的」。move 的意思就是转移所有权。当然,不是所有的类型都是 move 的,对于诸如 u8i32f16 这种基础类型在你赋值时是不会 move 的。那么有没有办法,让那些复杂或者用户自定义类型也能像其他语言一样,将一个变量赋值给另一个变量,并且不会转义所有权呢?

答案是有的。你只要为那个目标类型实现 Copy trait。接下来,我们为上方的 Point 类型实现 Copy trait。

#[derive(Debug)]
struct Point2 {
    x_value: i32,
    y_value: i32,
}

impl Copy for Point2 {
   
}

impl Clone for Point2{
    fn clone(&self) -> Point2 {
        *self
    }
}

pub fn has_copy() {
    let v1 = Point2 {
        x_value: 1,
        y_value: 2,
    };
    let mut v2 = v1;
    println!("{:?}", v1);
    v2.x_value += 1;
    println!("{:?}", v1);
    println!("{:?}", v2);
}
/// 输出
/// ```
/// Point2 { x_value: 1, y_value: 2 }
/// Point2 { x_value: 1, y_value: 2 }
/// Point2 { x_value: 2, y_value: 2 }
/// ```

通过上面的例子,可以看出,为 Point2 实现 CopyClone trait,即可让自定义类型自由地赋值,并且不会转移所有权。可不幸的是,不是所有的类型都能 Copy 和 Clone 的。下面是书中对 Copy 的介绍:

Copy的全名是std::marker::Copy。请大家注意,std::marker模块里面所有的trait都是特殊的trait。目前稳定的有四个,它们是Copy、Send、Sized、Sync。它们的特殊之处在于:它们是跟编译器密切绑定的,impl这些trait对编译器的行为有重要影响。在编译器眼里,它们与其他的trait不一样。这几个trait内部都没有方法,它们的唯一任务是给类型打一个“标记”,表明它符合某种约定——这些约定会影响编译器的静态检查以及代码生成。

Copy这个trait在编译器的眼里代表的是什么意思呢?简单点总结就是,如果一个类型impl了Copy trait,意味着任何时候,我们都可以通过简单的内存复制(在C语言里按字节复制memcpy)实现该类型的复制,并且不会产生任何内存安全问题。 -- 《深入浅出Rust》