RUST 每日一省:copy&clone的异同

Rust中有两个类似的trait—— Copy和Clone;今天来谈一谈这两个trait。

Copy

定义

实现Copy trait内部实现

pub trait Copy: Clone { }

        此Copytrait继承自Clone trait, 意味着, 要实现Copy trait的类型, 必须实现Clone trait中定义的方法。Copy位于std::marker::Copy。 我们可以看到Copy trait内部都没有方法, 它们的唯一任务是给类型打一个“标记”—— 我们都可以通过简单的内存复制实现“标记”类型的复制。一旦一个类型实现了Copy trait, 那么它在变量绑定、 函数参数传递、 函数返回值传递等场景下, 都是copy语义, 而不再是默认的move语义。

实现条件 
        常见的数字类型、 bool类型、 共享借用指针&, 都是具有Copy属性的类型。 而Box、 Vec、 可写借用指针&mut等类型都是不具备Copy属性的型。对于数组类型, 如果它内部的元素类型是Copy, 那么这个数组也是Copy类型。对于元组tuple类型, 如果它的每一个元素都是Copy类型, 那么这个tuple也是Copy类型。struct和enum类型不会自动实现Copy trait。 只有当struct和enum内部的每个元素都是Copy类型时, 编译器才允许我们针对此类型实现Copytrait。

Clone

定义
Clone位于std::clone::Clone。 它的实现如下:

pub trait Clone : Sized {
fn clone(&self) -> Self;
fn clone_from(&mut self, source: &Self) {
*self = source.clone()
}
}

        它有两个关联方法, 分别是clone_from和clone, clone_from是有默认实现的, 依赖于clone方法的实现。 clone方法没有默认实现, 需要手动实现。

实现
        对于Box类型, clone执行的是“深复制”; 而对于Rc类型, clone做的事情就是把引用计数值加1。虽然Rust中的clone方法一般是用来执行复制操作的, 但是如果在自定义的clone函数中做点别的什么工作, 编译器也没办法禁止。 你可以根据需要在clone函数中编写任意的逻辑。但是有一条规则需要注意: 对于实现了copy的类型, 它的clone方法应该跟copy语义相容, 等同于按字节复制。

derive自动实现


       因为实现Copy Clone这样的trait基本都是一个重复而无聊的工作。 因此我们可以使用derive、帮我们自动生成impl Copy和impl Clone这样的代码。 自动生成的clone方法, 会依次调用每个成员的clone方法。使用方法如下:

#[derive(Copy, Clone, Debug)]
struct Csdns;

总结


Copy和Clone两者的区别和联系如下。

  • Copy内部没有方法, Clone内部有两个方法。由于Copy trait没有定义任何方法,所以不会有任何额外的代码在这一过程中得到执行。这也就是说,可以认为复制值会非常快。
  • Copy trait是给编译器用的, 告诉编译器这个类型默认采用copy语义, 而不是move语义。 Clone trait是给程序员用的,必须手动调用clone方法。
  • Copy trait不是想实现就能实现的, 它对类型是有要求的, 有些类型不可能impl Copy。 而Clone trait则没有什么前提条件, 任何类型都可以实现。
  • Copy trait规定了这个类型在执行变量绑定、 函数参数传递、 函数返回等场景下,必然执行的是“简单内存复制”操作, 这是由编译器保证的, 程序员无法控制。Clone trait里面的clone方法究竟会执行什么操作, 则是取决于程序员自己写的逻辑。 一般情况下, clone方法应该执行一个“深复制”操作。
  • ·如果你确实不需要Clone trait执行其他自定义操作(绝大多数情况都是这样) , 编译器提供了一个工具, 我们可以在一个类型上添加#[derive(Clone) ], 来让编译器帮我们自动生成那些重复的代码。 编译器自动生成的clone方法非常机械, 就是依次调用每个成员的clone方法。

猜你喜欢

转载自blog.csdn.net/xq723310/article/details/130217182
今日推荐