趣谈 Rust 的 Copy trait 和 Clone trait

server/2024/9/24 8:08:38/

Copy_trait__0">一、Copy trait 的关键作用

Rust 程序中的变量可以分成两类:实现 Copy trait 的和没实现 Copy trait 的。这有啥区别?当然很重要!

  • 实现 Copy trait 的变量: 不存在所有权问题,可以随意赋值给其他变量,可以随意当参数传递给函数。因为每次赋值或函数传参数,实现 Copy trait 的变量都是把自己的一个完整的拷贝给了别人,而自身不因此受任何牵连和副作用影响。Rust 的整数、浮点数等简单数据类型,都是实现 Copy trait 的。
  • 未实现 Copy trait 的变量: 这类变量内部一般都有指针或变量引用,如果把这样的变量赋值给其他变量,当前变量就会失去所有权。因此,这类变量需要接受所有权、生命周等期机制来进行有效管理。

Copy_trait__6">二、我的数据类型需要实现 Copy trait 吗?

如果你的数据类型包含数据量较大,而且你用内部的指针指向这些大的数据块,那么你完整复制这样的变量需要很大的代价,这种情况下,建议不要实现 Copy trait。因为在代码中,赋值语句、函数调用等场合,一不小心就会触发 copy 操作,影响程序效率。

相反,你可以利用 clone 方法显式复制变量。

Clone_trait_10">三、Clone trait

CloneCopy 都是复制当前变量,产生一个副本,二者的差别在于 Rust 语法或语义。Clone方法表明可以用显式的方法产生一个变量的副本,这一般意味着当前变量内部可能有指针,部分数据可能在堆上分配。同时也常常意味着这类变量的使用存在所有权转移问题。

clone 和 copy 这两种方法的实现代码,没有什么区别,区别就在于 Rust 的语法和语义方面。

Copy__15">四、包含指针的数据类型一定不能实现 Copy 操作吗?

一般来讲是这样的,但不排除特殊需要。

为便于理解这个问题,我们先看一个例子:

rust">let a = Arc::new(123);
let b = a.clone();

从 Rust 语义上看,a、b 是两个完全独立的变量。从编程的角度看,后续代码认为 a、b 不存在所有权转移问题,他们在存储空间上不存在任何个联系。但是,实际上二者是共享数据的,因为 Arc 是一个共享计数指针。

这个例子告诉我们,如果有必要,可以用一些技巧欺骗 Rust 编译器的。所以我设想,Arc 这样的数据类型,与其不厌其烦地调用 clone 复制数据,倒不如直接实现 Copy trait,这样的话,上面的代码可以写成下面的形式:

rust">let a = Arc::new(123);
let b = a;

注意,如果 Arc 实现了 Copy trait,那么编译器认为 let b = a 只是把数据复制了一个完整、独立的副本,变量 a 中数据的所有权并没有转移。当然,Rust 并没有为 Arc 实现 trait,但我坚信,未来我们一定能看到有 Rust 代码库实现类似的机制。

总结

在 Rust 中,CopyClone 是两个重要的 trait,它们允许开发者复制数据的实例。尽管这两个 trait 都与复制有关,但它们之间有一些重要的区别。

Copy_Trait_36">Copy Trait

Copy trait 是一个标记 trait,没有定义任何方法。如果一个类型实现了 Copy,那么它表明该类型的值可以通过简单的位拷贝来复制,而不会导致任何运行时开销或可能的副作用。换句话说,Copy 类型的值在赋值或作为函数参数传递时,不需要显式地调用 .clone() 或其他复制方法,而是可以隐式地、低成本地进行位拷贝。

要实现 Copy trait,一个类型必须满足以下条件:

  1. 类型的所有成员都必须是 Copy 的。
  2. 没有使用到堆分配(例如,不包含 Box, Vec, 或 String 这样的类型)。
  3. 不包含任何形式的可变引用或借用。

由于 Copy 允许隐式复制,所以应该谨慎地为其实现,以避免意外地多次复制可能导致的问题。

Clone_Trait_48">Clone Trait

Copy 不同,Clone trait 定义了一个名为 clone 的方法,它返回一个与原始对象具有相同值的新对象。如果一个类型实现了 Clone,那么它可以使用 .clone() 方法来显式地创建一个副本。

Copy 相比,Clone 更加通用和灵活。例如,它可以用于复制那些包含堆上数据的类型,这些数据不能简单地通过位拷贝来复制。

区别

  1. 隐式与显式Copy 是隐式的,而 Clone 需要显式调用 .clone() 方法。
  2. 性能Copy 是低成本的位拷贝,而 Clone 可能涉及更复杂的复制操作,特别是当涉及到堆上数据时。
  3. 限制:不是所有类型都可以实现 Copy,因为它有一些严格的限制。但大多数类型都可以实现 Clone
  4. 用途Copy 主要用于优化和简化代码,而 Clone 提供了一种更通用的复制机制。

总之,当你知道一个类型可以通过简单的位拷贝来安全地复制时,你可以为其实现 Copy。如果你需要一种更通用的复制机制,或者当类型包含堆上数据时,你应该使用 Clone


http://www.ppmy.cn/server/2404.html

相关文章

Office 2024安装教程(附免费安装包资源)

鼠标右击软件压缩包,选择“解压到Office 2024安装包”。 打开解压后的文件夹,鼠标右击“YAOCTRI_Installer”选择“以管理员身份运行”。 输入数字“1”自动开始安装。 软件正在安装,请耐心等待,谢谢。 安装完成,点击“…

Qt | 事件第一节(QApplication、QGuiApplication、QCoreApplication)

一、QApplication、QGuiApplication、QCoreApplication 简介 1、继承关系见下图,其中左侧为顶级父类 2、一个程序中只能有一个 QCoreApplication 及其子类的对象。 3、QCoreApplication:主要提供无 GUI 程序的事件循环。 4、QGuiApplication:用于管理 GUI 程序的控制流和…

mysql like 查询包含%

在MySQL中,LIKE查询是用来搜索列中的指定模式的。如果想在LIKE查询中包含百分号(%),需要在LIKE查询中使用转义字符。 解决方案1: 可以使用REPLACE函数替换想要查询的字符串中的百分号。例如,如果想要查询…

【Hadoop大数据技术】——Flume日志采集系统(学习笔记)

📖 前言:在大数据系统的开发中,数据收集工作无疑是开发者首要解决的一个难题,但由于生产数据的源头丰富多样,其中包含网站日志数据、后台监控数据、用户浏览网页数据等,数据工程师要想将它们分门别类的采集…

【解决】Spring Boot创建项目常见问题

🎥 个人主页:Dikz12🔥个人专栏:Spring学习之路📕格言:吾愚多不敏,而愿加学欢迎大家👍点赞✍评论⭐收藏 目录 idea无maven选项 无效发行版17 类⽂件具有错误的版本 61.0, 应为 …

python中的设计模式:单例模式

设计模式 设计模式的确切数量并没有一个统一的标准,因为不同的资料和文献可能会对设计模式的定义和分类有所不同。然而,最常见的设计模式集合是由Erich Gamma、Richard Helm、Ralph Johnson和John Vlissides这四位作者在他们的著作《设计模式&#xff1…

js判断文件后缀是图片

function isImage(filename) { // 获取文件的扩展名 const extension filename.split(‘.’).pop().toLowerCase(); // 常见的图片文件扩展名 const imageExtensions [‘jpg’, ‘jpeg’, ‘png’, ‘gif’, ‘bmp’, ‘webp’, ‘svg’]; // 检查文件扩展名是否在常见图片…

iOS知识点 --- UITableView优化

iOS 中的 UITableView 是一个非常常见的用于展示列表数据的组件,由于其在滚动时需要实时加载和更新大量单元格,因此对性能要求较高。以下是一些针对 UITableView 的性能优化策略: 合理利用重用机制: 设置正确的 reuseIdentifier 并…