Borrow trait

概述

Borrow trait用来获取自身内部数据的引用

目的是能通过这个引用获取内部的数据,就是说:通过引用看到的数据,应该和通过所有权看到的数据一致

定义

  1. pub trait Borrow<Borrowed: ?Sized> {
  2. fn borrow(&self) -> &Borrowed;
  3. }

和AsRef对比

  • Borrow trait用来借用内部数据,而AsRef trait用来做引用类型转换
  • 实现Borrow trait的类型表示它能够被借用,实现AsRef trait了类型表示它能被类型转换
  • AsRef trait更适合用作trait bound

使用

  1. 为不同类型实现特定的借用方式

例如:String类型实现了Borrow<str>,拿到的引用类型为:&str

  1. impl Borrow<str> for String {
  2. #[inline]
  3. fn borrow(&self) -> &str {
  4. &self[..]
  5. }
  6. }
  1. 为不同类型实现通用的借用方式

例如:Rc<T>类型实现了Borrow<T>,拿到的引用类型为:&T

  1. impl<T: ?Sized> borrow::Borrow<T> for Rc<T> {
  2. fn borrow(&self) -> &T {
  3. &**self
  4. }
  5. }

Cow enum

定义

  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. }

Cow是枚举类型,代表两种情况之一:

  • Borrowed,表示Cow目前提供的是对数据的借用
  • Owned,表示Cow对克隆了数据,并有数据的所有权

Cow旨在提高性能(减少复制),同时增加灵活性,因为大多数时候,业务场景是多读少写。 使用Cow,这可以以统一、规范的形式实现,其中对象复制仅在需要写入时进行一次。 这可能会显着减少复制次数

创建方式

创建Cow类型变量:

  1. // 通过不可变借用创建
  2. // 以下效果相同
  3. Cow::from(&B)
  4. Cow::Borrow(&B)
  5. // 通过所有权创建
  6. // 以下效果相同
  7. Cow::from(B)
  8. Cow::Owned(B)

状态转换

在创建Cow<B>类型数据后,可以有三种操作:

  • 直接调用**B**不可变方法当作智能指针使用,提供对类型的透明不可变访问,因为Cow实现了**Deref** trait
  • to_mut()
    • 如果**clone**,则clone,此时拥有变量的所有权,并获取其可变引用
    • 如果已经**clone**。则直接获取其可变引用
  • into_owned()
    • 进行clone操作,即内存复制/创建新对象
    • 此方法的参数为 self 类型,将“消耗”该类型的原始实例,此后该类型的原始实例的生命周期将结束,并且不能在Cow多次调用

示例

  1. #![feature(cow_is_borrowed)]
  2. use std::borrow::Cow;
  3. fn abs_all(input: &mut Cow<[i32]>) {
  4. for i in 0..input.len() {
  5. let v = input[i];
  6. if v < 0 {
  7. // 调用to_mut()方法,如果不是Owned状态,则会发生clone
  8. input.to_mut()[i] = -v;
  9. }
  10. }
  11. }
  12. fn main(){
  13. // 没有调用过to_mut()方法,所以未发生clone
  14. let slice = [0, 1, 2];
  15. let mut input = Cow::from(&slice[..]);
  16. abs_all(&mut input);
  17. println!("{:?}",input.is_borrowed()); // true
  18. // 需要修改数据,调用过to_mut()方法,所以发生过clone,但仅发生过一次
  19. let slice = [-1, 0, 1];
  20. let mut input = Cow::from(&slice[..]);
  21. abs_all(&mut input);
  22. println!("{:?}",input.is_owned()); // true
  23. println!("{:?}",input); // [1, 0, 1]
  24. // 通过所有权创建, 本身已经是owned的了
  25. let mut input = Cow::from(vec![-1, 0, 1]);
  26. abs_all(&mut input);
  27. println!("{:?}",input.is_owned()); // true
  28. }