Borrow trait
概述
Borrow trait用来获取自身内部数据的引用
目的是能通过这个引用获取内部的数据,就是说:通过引用看到的数据,应该和通过所有权看到的数据一致
定义
pub trait Borrow<Borrowed: ?Sized> {fn borrow(&self) -> &Borrowed;}
和AsRef对比
Borrow trait用来借用内部数据,而AsRef trait用来做引用类型转换- 实现
Borrow trait的类型表示它能够被借用,实现AsRef trait了类型表示它能被类型转换 AsRef trait更适合用作trait bound
使用
- 为不同类型实现特定的借用方式
例如:String类型实现了Borrow<str>,拿到的引用类型为:&str
impl Borrow<str> for String {#[inline]fn borrow(&self) -> &str {&self[..]}}
- 为不同类型实现通用的借用方式
例如:Rc<T>类型实现了Borrow<T>,拿到的引用类型为:&T
impl<T: ?Sized> borrow::Borrow<T> for Rc<T> {fn borrow(&self) -> &T {&**self}}
Cow enum
定义
pub enum Cow<'a, B>whereB: 'a + ToOwned + ?Sized,{Borrowed(&'a B),Owned(<B as ToOwned>::Owned),}
Cow是枚举类型,代表两种情况之一:
Borrowed,表示Cow目前提供的是对数据的借用Owned,表示Cow对克隆了数据,并有数据的所有权
Cow旨在提高性能(减少复制),同时增加灵活性,因为大多数时候,业务场景是多读少写。 使用Cow,这可以以统一、规范的形式实现,其中对象复制仅在需要写入时进行一次。 这可能会显着减少复制次数。
创建方式
创建Cow类型变量:
// 通过不可变借用创建// 以下效果相同Cow::from(&B)Cow::Borrow(&B)// 通过所有权创建// 以下效果相同Cow::from(B)Cow::Owned(B)
状态转换
在创建Cow<B>类型数据后,可以有三种操作:
- 直接调用
**B**的不可变方法当作智能指针使用,提供对类型的透明不可变访问,因为Cow实现了**Deref** trait to_mut():- 如果未
**clone**过,则clone,此时拥有变量的所有权,并获取其可变引用 - 如果已经
**clone**过。则直接获取其可变引用
- 如果未
into_owned()- 进行
clone操作,即内存复制/创建新对象 - 此方法的参数为 self 类型,将“消耗”该类型的原始实例,此后该类型的原始实例的生命周期将结束,并且不能在
Cow上多次调用。
- 进行
示例
#![feature(cow_is_borrowed)]use std::borrow::Cow;fn abs_all(input: &mut Cow<[i32]>) {for i in 0..input.len() {let v = input[i];if v < 0 {// 调用to_mut()方法,如果不是Owned状态,则会发生cloneinput.to_mut()[i] = -v;}}}fn main(){// 没有调用过to_mut()方法,所以未发生clonelet slice = [0, 1, 2];let mut input = Cow::from(&slice[..]);abs_all(&mut input);println!("{:?}",input.is_borrowed()); // true// 需要修改数据,调用过to_mut()方法,所以发生过clone,但仅发生过一次let slice = [-1, 0, 1];let mut input = Cow::from(&slice[..]);abs_all(&mut input);println!("{:?}",input.is_owned()); // trueprintln!("{:?}",input); // [1, 0, 1]// 通过所有权创建, 本身已经是owned的了let mut input = Cow::from(vec![-1, 0, 1]);abs_all(&mut input);println!("{:?}",input.is_owned()); // true}
