rust copy 和 clone 区别_rust copy clone-程序员宅基地

技术标签: rust  

Rust 中有两个常见的 trait,Clone 和 Copy,许多初学者没有搞明白。今天我们来专门谈一谈这两个 trait。

Copy 的含义

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

Copy 这个 trait 在编译器的眼里代表的是什么意思呢?简单点总结就是说,如果一个类型 impl 了 Copy trait,意味着任何时候,我们可以通过简单的内存拷贝(C语言的按位拷贝memcpy)实现该类型的复制,而不会产生任何问题。

一旦一个类型实现了 Copy trait,那么它在变量绑定、函数参数传递、函数返回值传递等场景下,它都是 copy 语义,而不再是默认的 move 语义。

Copy 的实现条件

并不是所有的类型都可以实现Copy trait。Rust规定,对于自定义类型,只有所有的成员都实现了 Copy trait,这个类型才有资格实现 Copy trait。

常见的数字类型、bool类型、共享借用指针&,都是具有 Copy 属性的类型。而 Box、Vec、可写借用指针&mut 等类型都是不具备 Copy 属性的类型。

对于数组类型,如果它内部的元素类型是Copy,那么这个数组也是Copy类型。

对于tuple类型,如果它的每一个元素都是Copy类型,那么这个tuple会自动实现Copy trait。

对于struct和enum类型,不会自动实现Copy trait。而且只有当struct和enum内部每个元素都是Copy类型的时候,编译器才允许我们针对此类型实现Copy trait。

我们可以认为,Rust中只有 POD(C++语言中的Plain Old Data) 类型才有资格实现Copy trait。在Rust中,如果一个类型只包含POD数据类型的成员,没有指针类型的成员,并且没有自定义析构函数(实现Drop trait),那它就是POD类型。比如整数、浮点数、只包含POD类型的数组等,都属于POD类型。而Box、 String、 Vec等,不能按 bit 位拷贝的类型,都不属于POD类型。但是,反过来讲,并不是所有的POD类型都应该实现Copy trait。

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 方法没有默认实现,需要我们手动实现。

clone 方法一般用于“基于语义的复制”操作。所以,它做什么事情,跟具体类型的作用息息相关。比如对于 Box 类型,clone 就是执行的“深拷贝”,而对于 Rc 类型,clone 做的事情就是把引用计数值加1。

虽然说,Rust中 clone 方法一般是用来执行复制操作的,但是你如果在自定义的 clone 函数中做点什么别的工作编译器也没法禁止,你可以根据情况在 clone 函数中编写任意的逻辑。但是有一条规则需要注意:对于实现了 Copy 的类型,它的 clone 方法应该跟 Copy 语义相容,等同于按位拷贝。

自动 derive

绝大多数情况下,实现 Copy Clone 这样的 trait 都是一个重复而无聊的工作。因此,Rust提供了一个 attribute,让我们可以利用编译器自动生成这部分代码。示例如下:

#[derive(Copy, Clone)]
struct MyStruct(i32);

这里的 derive 会让编译器帮我们自动生成 impl Copy 和 impl Clone 这样的代码。自动生成的 clone 方法,就是依次调用每个成员的 clone 方法。

通过 derive 方式自动实现 Copy 和手工实现 Copy 有一丁点的微小区别。当类型具有泛型参数的时候,比如 struct MyStruct<T>{},通过 derive 自动生成的代码会自动添加一个 T: Copy 的约束。

目前,只有一部分固定的特殊 trait 可以通过 derive 来自动实现。将来 Rust 会允许自定义的 derive 行为,让我们自己的 trait 也可以通过 derive 的方式自动实现。

总结

Copy 和 Clone 两者的区别和联系有:

  1. Copy内部没有方法,Clone内部有两个方法。
  2. Copy trait 是给编译器用的,告诉编译器这个类型默认采用 copy 语义,而不是 move 语义。Clone trait 是给程序员用的,我们必须手动调用clone方法,它才能发挥作用。
  3. Copy trait不是你想实现就实现,它对类型是有要求的,有些类型就不可能 impl Copy。Clone trait 没有什么前提条件,任何类型都可以实现(unsized 类型除外)。
  4. Copy trait规定了这个类型在执行变量绑定、函数参数传递、函数返回等场景下的操作方式。即这个类型在这种场景下,必然执行的是“简单内存拷贝”操作,这是由编译器保证的,程序员无法控制。Clone trait 里面的 clone 方法究竟会执行什么操作,则是取决于程序员自己写的逻辑。一般情况下,clone 方法应该执行一个“深拷贝”操作,但这不是强制的,如果你愿意,也可以在里面启动一个人工智能程序,都是有可能的。
  5. 如果你确实需要Clone trait执行“深拷贝”操作,编译器帮我们提供了一个工具,我们可以在一个类型上添加#[derive(Clone)],来让编译器帮我们自动生成那些重复的代码。
  6. 然而Rust语言规定了当T: Copy的情况下,Clone trait代表的含义。即:当某变量let t: T;,符合T: Copy时, 它调用 let x = t.clone() 方法的时候,它的含义必须等同于“简单内存拷贝”。也就是说,clone的行为必须等同于let x = std::ptr::read(&t);,也等同于let x = t;。当T: Copy时,我们不要在Clone trait里面乱写自己的逻辑。所以,当我们需要指定一个类型是 Copy 的时候,最好顺便也指定它 Clone 的行为,就是编译器为我们自动生成的那个逻辑。正因为如此,在希望让一个类型具有 Copy 性质的时候,一般使用 #[derive(Copy, Clone)] 这种方式,这种情况下它们俩最好一起出现,避免手工实现 Clone 导致错误。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/shangsongwww/article/details/118992654

智能推荐

Cisco Packet Tracer下载和安装-程序员宅基地

文章浏览阅读1.5k次,点赞2次,收藏6次。有一点需要注意的是,要完成一些步骤才能获得下载资格,选择accept agreement,下一步。下载后,双击进入安装界面,下一步。第一个要选,都选也行,然后下一步。选择要安装的地址,然后下一步。选择Chinese.ptl。再次进入就是正文了。_cisco packet tracer下载

css display:flex实现元素垂直居中_cssdisplayflex居中-程序员宅基地

文章浏览阅读9k次。在此之前元素垂直居中我使用的是绝对定位absolute或固定定位fixed如何用flex实现元素垂直居中呢,父级包括子级&lt;div class='itemBox'&gt; &lt;div&gt;boxboxboxboxboxboxboxboxboxboxbox&lt;/div&gt;&lt;/div&gt; .itemBox{display: flex;..._cssdisplayflex居中

计算机藏应用,应用隐藏大师计算器-程序员宅基地

文章浏览阅读6.2k次。应用隐藏大师计算器app是一款可以将自己隐私的软件进行隐蔽加密的软件,应用隐藏大师计算器最新版能把自己的图标换成计算器图标,名字也能换成计算器,隐藏应用,隐藏软件或游戏,所有被隐藏的东西都被藏到了这款有着计算机长相和密码的软件中,感兴趣的小伙伴们赶紧来下载应用隐藏大师计算器吧!这是一款把应用隐藏起来的软件,表面上这是一个计算机,实际上这是一个藏宝箱,各位绅士必备,包括照片 视频 什么的都可以在里面..._计算机里藏手机软件

SOLIDWORKS 2021 SP5.0 安装教程_solidworks2021序列号-程序员宅基地

文章浏览阅读1.5w次,点赞12次,收藏43次。SOLIDWORKS 安装教程_solidworks2021序列号

PTA-自助扫码_已知某超市有自助收银机m台,每件商品扫码时间都相等,均为1秒,现有n个顾客准备结账-程序员宅基地

文章浏览阅读4.3k次,点赞6次,收藏8次。PTA-自助扫码题意扫码支付如今已普及应用在大型超市,街边小贩等多个消费支付的场景,刷脸支付也在商超零售场景逐渐应用,很多的大型超市引进自助收银系统,实现自助结账应用。已知某超市有自助收银机m台,每件商品扫码时间都相等,均为1秒,现有n个顾客准备结账,初始顺序已经确定为1-n,编号i号顾客购买的商品件数为ci,当其中某名顾客扫完所有商品后,下一名排队等候付款的顾客马上使用刚空闲的这台自助收银机,即忽略支付时间和自助收银机换人的时间开销,则所有顾客完成结账需要多少时间?pta自动扫码提示:以下是_已知某超市有自助收银机m台,每件商品扫码时间都相等,均为1秒,现有n个顾客准备结账

电脑管理android手机版下载失败怎么办,腾讯手机管家PC版轻松解决Android文件管理难题...-程序员宅基地

文章浏览阅读325次。智能手机使用时间越来越长,照片、视频、音乐、应用软件等不断增多。起初,还能把各类文件管理的有条不紊,但随着不断的拷贝、新建、删除,眼看着手机中的文件夹越来越多、越来越复杂,手机中的文件资料也开始像杂货铺一样乱七八糟,直到有一天自己都无法在杂乱的手机文件中找到刚拷贝进去的资料。手机虽然智能了,但文件的管理却没跟的上智能的脚步,对于智能机用户而言,这已经不再是一个小问题。小编就深受文件管理难之苦,不过..._电脑修改手机安卓文件夹失败

随便推点

电脑预装linux系统,电脑预装Linux第三方系统怎么破?看外行人重装Win10系统的精准攻略...-程序员宅基地

文章浏览阅读275次。电脑预装Linux第三方系统怎么破?看外行人重装Win10系统的精准攻略2020-03-10 20:12:2628点赞72收藏82评论创作立场声明:予人点赞,手有余香,欢迎值友们一起交流探讨。一、前言上周女神节,楼主给老婆大人入了一台MagicBook15笔记本电脑,配置为锐龙5处理器+8G内存+512G固态硬盘。而出厂时电脑预装了Linux第三方系统,着实比较鸡肋——主要是楼主为了省钱,购买的此..._电脑第三方linux

SUN RPC的传输层实现机制_sun-rpc发送数据帧-程序员宅基地

文章浏览阅读3.4k次。通信语义为保证RPC语义的实现,我们必须在良种可能中进行选择。一方面,为尽量使远程过程调用的行为像一个本地过程调用,RPC应该使用一种像TCP这样可靠的运输,而且应该对程序员保证可靠性。另一方面,为允许程序员使用高效率的、无连接的运输协议,远程过程调用机制应当支持用UDP这样的数据报协议进行通信。因为UDP传输的不可靠性,在传输过程中可能因为报文的丢失,使得调用者无法做出应答,而导致远程过_sun-rpc发送数据帧

postman:模拟发送一个需要cookie认证的请求-程序员宅基地

文章浏览阅读251次。1、chrome 已安装插件intercept。 由于chrome安全的限制,发不出带cookie的请求。如果想要发送带cookie的请求,需要开启Interceptor。 2、chrome 浏览器要设置打开,在运行期间浏览器要一直打开。 3、本人是用fiddler对app的请求..._postman 模仿cookie jsessonid

org.webrtc.VideoFrame转byte[]_i420buffer转byte数组-程序员宅基地

文章浏览阅读915次,点赞2次,收藏2次。前言 项目需要,获取WebRTC封装的VideoFrame中的byte,效率很慢,仅供参考方法 VideoFrame自带转I420的接口,转I420后,根据格式去除Y,U,V各分量,然后拷贝到数组中(通过实现onFrame接口,然后addSink实现接口的对象获取到VideoFrame)代码public void onFrame(VideoFrame var1) { VideoFrame.I420Buffer buffer = v..._i420buffer转byte数组

linux c 编程手册,Linux C/C++编程手册查阅方法-程序员宅基地

文章浏览阅读422次。Linux Programmer's Manual & User Commandshttps://www.kernel.org/doc/man-pages/ 搜索框输入epoll调用搜索引擎查找在线搜索查看man手册(比如查epoll),可以直接收藏,方便下次点击搜索:http://global.bing.com/search?q=site:man7.org epollThe Linux ..._fmax c++ linux手册页

计算机上用户和组的意义,在域中管理用户和组-程序员宅基地

文章浏览阅读1.5k次。本章要点:Ø 用户帐号和组概述Ø 创建和管理用户帐号Ø 在域中使用组的策略3.1 用户帐号和组概述活动目录是一种保存和维护网络资源所需的数据的目录服务数据库。域用户帐号在AD中创建一次,就能在域中的工作站上登录访问网络资源。组通常是用户帐号的集合,可以用来高效管理域资源的访问。管理对 Active Directory 目录服务拥有管理权限的用户和组是网络系统保护的重要组成部分。获得 Active ..._用户和组管理的作用

推荐文章

热门文章

相关标签