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>
where
B: '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状态,则会发生clone
input.to_mut()[i] = -v;
}
}
}
fn main(){
// 没有调用过to_mut()方法,所以未发生clone
let 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()); // true
println!("{:?}",input); // [1, 0, 1]
// 通过所有权创建, 本身已经是owned的了
let mut input = Cow::from(vec![-1, 0, 1]);
abs_all(&mut input);
println!("{:?}",input.is_owned()); // true
}