• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

Rust写时复制CowT

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

写时复制(Copy on Write)技术是一种程序中的优化策略,多应用于读多写少的场景。主要思想是创建对象的时候不立即进行复制,而是先引用(借用)原有对象进行大量的读操作,只有进行到少量的写操作的时候,才进行复制操作,将原有对象复制后再写入。这样的好处是在读多写少的场景下,减少了复制操作,提高了性能。

Rust中对应这种思想的是智能指针Cow<T>,定义如下:

pub enum Cow<'a, B> 
where
    B: 'a + ToOwned + 'a + ?Sized, 
 {
    Borrowed(&'a B),    //用于包裹引用
    Owned(<B as ToOwned>::Owned),   //用于包裹所有者
}

可以看到是一个枚举体,包括两个可选值,一个是“借用”,一个是“所有”。具体含义是:以不可变的方式访问借用内容,在需要可变借用或所有权的时候再克隆一份数据。

下面举个例子说明Cow<T>的应用:

use std::borrow::Cow;

fn abs_all(input: &mut Cow<[i32]>) {
    for i in 0..input.len() {
        let v = input[i];
        if v < 0 {
            input.to_mut()[i] = -v;
        }
    }

    println!("value: {:?}", input);
}

fn main() {
    // 只读,不写,没有发生复制操作
    let a = [0, 1, 2];
    let mut input = Cow::from(&a[..]);
    abs_all(&mut input);
    assert_eq!(input, Cow::Borrowed(a.as_ref()));

    // 写时复制, 在读到-1的时候发生复制
    let b = [0, -1, -2];
    let mut input = Cow::from(&b[..]);
    abs_all(&mut input);
    assert_eq!(input, Cow::Owned(vec![0,1,2]) as Cow<[i32]>);

    // 没有写时复制,因为已经拥有所有权
    let mut input = Cow::from(vec![0, -1, -2]);
    abs_all(&mut input);
    assert_eq!(input, Cow::Owned(vec![0,1,2]) as Cow<[i32]>);
    
    let v = input.into_owned();
    assert_eq!(v, [0, 1, 2]);
}

上面这个用例已经讲明了Cow<T>的使用,下面我们继续探索一下Cow<T>的实现细节。重点关注to_mutinto_owned的实现。

  • to_mut :就是返回数据的可变引用,如果没有数据的所有权,则复制拥有后再返回可变引用;
  • into_owned :获取一个拥有所有权的对象(区别与引用),如果当前是借用,则发生复制,创建新的所有权对象,如果已拥有所有权,则转移至新对象。
impl<B: ?Sized + ToOwned> Cow<'_, B> {
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn to_mut(&mut self) -> &mut <B as ToOwned>::Owned {
        // 如果时借用,则进行复制;如果已拥有所有权,则无需进行复制
        match *self {
            Borrowed(borrowed) => {
                *self = Owned(borrowed.to_owned());
                match *self {
                    Borrowed(..) => unreachable!(),
                    Owned(ref mut owned) => owned,
                }
            }   
            Owned(ref mut owned) => owned,  //这里解释了上个例子中,已拥有所有权的情况,无需再复制
        }
    }
    
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn into_owned(self) -> <B as ToOwned>::Owned {
        // 如果当前是借用,则发生复制,创建新的所有权对象,如果已拥有所有权,则转移至新对象。
        match self {
            Borrowed(borrowed) => borrowed.to_owned(),
            Owned(owned) => owned,
        }
    }
}

最后,欢迎关注微信公众号,及时更新最新文章:


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
matlab回归分析发布时间:2022-07-18
下一篇:
MATLAB工具箱大全发布时间:2022-07-18
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap