Rust的Cow类型有什么用?详解Cow及其用途

打印 上一主题 下一主题

主题 840|帖子 840|积分 2522

Rust的智能指针有哪些?大多数人都能马上答出Box、Rc和Arc、Ref和在异步编程中很常见的Pin等等。不过,有一个可能经常被大多数人遗忘的类型,它功能强大,利用好了可以节省很多复制开销;它就是这篇文章的主角:Cow<B>。
什么是COW(Copy-On-Write)?

在开始之前,有必要先介绍一下COW(Copy-On-Write,写时复制)的概念。COW是一种用于资源管理的优化策略,在操作系统中应用非常广泛。COW的核心思想是当多个任务需要读取同一个资源(比如内存中的数据、文件)的时候,它们会共享同一份资源副本,而不是为每个任务复制一份资源副本。只有当某个任务需要修改这个资源时,才会为这个任务创建一份资源副本。
需要注意的是,上述的整个过程对任务(也就是程序员编写的用户程序)来说都是不可见的;对程序员来说,他并不知道他所使用的资源在发生写操作时才被真正地复制了一份,自始至终他仿佛就像在独占整份资源一样。
COW在文件系统、虚拟内存管理中都有非常成熟的应用;在编程语言中,也被广泛应用于优化字符串、集合的处理。
Cow:定义

Rust的Cow<B>是一个枚举类型,包含两个成员:Borrowed和Owned。不过,我们几乎不会直接用到它的成员,因为Cow<B>实现了Deref特征,这使得我们可以通过Deref转换这一语法糖来便捷地直接使用Cow<B>中的内容。有关Deref转换可以阅读我之前的文章。
  1. pub enum Cow<'a, B>
  2. where
  3.     B: 'a + ToOwned + ?Sized,
  4. {
  5.     Borrowed(&'a B),
  6.     Owned(<B as ToOwned>::Owned),
  7. }
复制代码
这种方案可以吗?仔细想想,当字节切片中有UTF-8中不支持的错误字符时,错误字符需要被替换成“�”;直接返回&str的话是做不了对字符串内容的修改的。
返回String呢?
顺着刚才的思路,因为我们可能需要修改字符串,所以我们就需要返回&str的栈上类型String,合情合理:
  1. use std::borrow::Cow;
  2. fn main() {
  3.     let foo = "Hello World";
  4.     let mut bar: Cow<str> = Cow::from(foo);
  5.     println!("{bar}");      // 这里没有发生复制
  6.    
  7.     bar.to_mut().push_str(" Rust");  // 这里发生了复制
  8.     println!("{bar}");
  9.    
  10.     println!("{foo}");      // 原来的字符串foo仍然可用,而且没有变化
  11. }
复制代码
不过,另一个问题冒出来了:虽然返回String完美地解决了修改字符串之后会导致新字符串无处存放的问题,但是如果旧的字符串(字节切片)不需要修改的话,也需要被复制到String中,这无形中增加了很多不必要的消耗;而且,字节切片中有错误字符是概率很小的事件,为了小概率事件影响拖累大概率发生的正常情况的性能,这值得吗?
这时,我一拍大腿:在需要修改时返回String,不需要修改时返回&str不就好了?
返回(Option, Option)(或者Either)
这样,上面所描述的性能和功能矛盾就解决了:
  1. use std::borrow::Cow;
  2. fn main() {
  3.     let str_ = "Hello World";
  4.     let string = String::from("Hello World!");
  5.    
  6.     let foo: Cow<str> = Cow::Borrowed(str_);
  7.     let bar: Cow<str> = Cow::Owned(string);
  8.    
  9.     // 这里string不再可用
  10.     // println!("{string}");
  11. }
复制代码
使用了Cow之后,它不仅可以在需要修改字符串时克隆并返回新数据,更可以在绝大多数普通情况之下直接借用数据;更妙的是,它可以享受Deref转换的语法糖,可谓十分完美!
总结

Cow是Rust中非常有用的一个类型,虽然日常开发中几乎用不到它,但是某些性能敏感的场景下善用Cow说不定会有奇效喔~

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

祗疼妳一个

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表