首页  »  用实例学习 Rust——所有权之“间接伤害”  »  用实例学习 Rust——所有权之“间接伤害”

用实例学习 Rust——所有权之“间接伤害”

《用实例学习 Rust——所有权之“间接伤害”》内容简介
用实例学习 Rust——所有权之“间接伤害”


上文通过共享所有权解决了变量移动语义的问题,但在最后我们也提到了共享所有权是无法修改原始数据的。但有的时候我们又确实需要修改原始数据怎么办?Rust 同样为这种场景提供了解决方案。当然这个解决方案也是要付出代价的。学习过 Rust 的人知道,如果出现了变量的可变引用,那么它就只能是唯一的存在,也就是说,不能再有另一个可变引用,也不能再有不可变引用了。下面我们来看看是如何做到的。

这里依然是创建库项目,为了使用性能测试宏,需要切换 Rust 到 nightly。使用如下命令:rustup default nightly。然后加入如下代码到文件的顶端:#![feature(test)]。

下面我们来创建几个函数:

fn using_refcell(min: i32, v: &RefCell<Vec<i32>>) { let sum: i32 = v.borrow().iter().sum(); if sum < min { v.borrow_mut().push(min - sum); }}fn using_cell(min: i32, v: &Cell<Vec<i32>>) { let mut vec = v.take(); let sum: i32 = vec.iter().sum(); if sum < min { vec.push(min - sum); } v.set(vec);}

这两个函数都完成了一个功能,就是传入一个值和一个数组,如果数组之和小于这个值,就把它们的差放进数组里。也就是说我们在函数中修改了外面数组的值。这两个函数分别使用了两种数据类型,RefCell 和 Cell。下面通过单元测试来看看 RefCell和 Cell 是如何运作的。

#[test]fn testing_refcell_cell() { let ref_cell = RefCell::new(vec![10, 20, 30]); using_refcell(70, &ref_cell); assert!(ref_cell.borrow().eq(&vec![10, 20, 30, 10])); let cell = Cell::from(vec![10, 20, 30]); using_cell(70, &cell); let v = cell.into_inner(); assert_eq!(v, vec![10, 20, 30, 10]);}

首先看看 using_refcell 函数,我们知道传数组参数时传的是引用 &,我们又知道传引用是无法修改原始值的,但我们的数组值是被 RefCell 包裹的,传的引用是RefCell的引用,RefCell 有两个函数 borrow 和 borrow_mut。顾名思义,borrow 函数可以获取 RefCell 包裹中的值的不可变引用,borrow_mut 函数可以获取 RefCell 包裹中的值的可变引用。在求和的时候我们不需要修改原始数组,因为使用的是 borrow 函数;最后在把新值 push 进数组中时使用的就是 borrow_mut 函数了,非常容易理解。在函数外面,我们比较的是引用。因为我们从 RefCell 只能得到引用,就像它的名字所表示的一样。

再来看看 using_cell 函数。数组是被 Cell 数据类型包裹起来的。在函数中,我们需要使用 Cell 的 take 函数把包裹的值取出来,然后使用 mut 修饰后才可以改变数组中的值。在函数的外面,通过使用 Cell 的 into_inner 函数,我们可以得到 Cell 包裹中的值,而不是引用,这就是它和 RefCell 的区别所在。

然而,RefCell 的使用是有隐患的,会引起 panic,为什么呢?先来看代码:

#[test]#[should_panic]fn failing_cells() { let ref_cell = RefCell::new(vec![10, 20, 30]); let _v = ref_cell.borrow(); refcell_test(60, &ref_cell); refcell_test(70, &ref_cell);}

我们知道不可变引用是可以有无数多次的。因此在把数组传入函数之前,我们先以不可变引用借用给了 _v 变量。然后我们把数组传递给了函数,在函数内部,首先再一次通过不可变引用借用给了变量 sum,这没有任何问题,完全合法。因为 sum 的值和 min 的值相等,所以函数执行完毕,回到主函数。紧接着,我们又一次调用了函数,但这次的 min 值是 70,大于 sum 值,就会进入 if 语句,以可变引用的方式借用了原始数组,这时,panic 发生了。为什么?之前我们已经说过,以可变引用的方式借用,是唯一的存在,在它借用之前,或者借用以后没归还之前,是不能有任何可变或者不可变引用方式的借用的。由于我们在调用函数之前已经借用给了变量 _v,按照规则,就不能再以可变引用的方式借用了,就会发生 panic。但编译器并没有给我们提示,也就是说,RefCell 会绕过 borrow checker,借用检查器。请大家一定要谨记这一点,编程方便了,不稳定性也就增加了。

就像 Rc 和 Arc 一样,这样在原始数据类型外面包裹一层肯定是有性能损耗的,下面我们来看看性能测试:

extern crate test;use test::Bencher;#[bench]fn regular_push(b: &mut Bencher) { let mut v = vec![]; b.iter(|| { for _ in 0..1_000 { v.push(10); } });}#[bench]fn refcell_push(b: &mut Bencher) { let v = RefCell::new(vec![]); b.iter(|| { for _ in 0..1_000 { v.borrow_mut().push(10); } });}#[bench]fn cell_push(b: &mut Bencher) { let v = Cell::new(vec![]); b.iter(|| { for _ in 0..1_000 { let mut vec = v.take(); vec.push(10); v.set(vec); } });}

这里我们测试了标准数组,RefCell,Cell 的 push 操作,在笔者的电脑上结果分别是:12147 ns/iter,16370 ns/iter, 25492 ns/iter。我们看到 RefCell 和原始性能相差无几,而 Cell 则 2 倍于原始性能。这也符合我们的预期,因为 Cell 每次迭代都要移动整个数组。

如有任何问题,请添加微信公众号“读一读我”。

1、问:用实例学习 Rust——所有权之“间接伤害”什么时候上映时间?

答:这部影片的上映时间是2024-04-26 20:06:23

2、问:用实例学习 Rust——所有权之“间接伤害”国产剧在哪个电视台播出?

答:用实例学习 Rust——所有权之“间接伤害”目前只有华数TV、1905电影网、咪咕视频、河塘影视等线上播出,而且还没有在电视上播出。

3、问:国产剧用实例学习 Rust——所有权之“间接伤害”演员表

答:在线观看非常完美是由达达执导,本·阿弗莱克,艾莉丝·布拉加,J.D.普拉多,戴奥·奥柯奈伊,杰夫·法赫,杰基·厄尔·哈利,威廉·菲克纳,赞恩·霍尔茨,鲁本·哈维尔·卡巴雷诺,凯莉·弗莱,桑迪·阿维拉,瑞恩·留萨基,哈拉·芬利,爱奥妮·奥利维亚·尼维斯,科瑞娜·卡尔德隆,劳伦斯·瓦尔纳多,德里克·罗素,达娜·温·刘,罗纳德·乔·瓦斯奎兹,海尔斯·杨领衔主演的国产剧。

4、问:哪个平台可以免费看用实例学习 Rust——所有权之“间接伤害”

答:免vip在线观看地址http://vk126.com/city.asp?id=2474

5、问:手机版免费在线点播有哪些网站?

答:hao123影视百度视频锦祥剧情百科网PPTV电影天堂

6、问:在线观看非常完美评价怎么样?

Mtime时光网网友评价:2023热播《用实例学习 Rust——所有权之“间接伤害”》,楚岩笑了笑,也不否认,继续道可前辈有没有想过,这一次结束后,上古前辈突破十二界,实力又提升了一大层,那此地的压力,必然也会增长,没有新的力量进入,这压力可就要前辈们自己承受了。

丢豆网网友评论:王勇强行挤出点笑容来,期盼着江虎能接受他的提议。结果江虎给了他一窝脚,冷笑道:你当老子是傻子吗刚刚老子可是亲眼看到有鬼手从宅子里伸出来,明显有鬼,这地方谁还敢要,谁敢住还两亿,二块钱老子也不要

游客bx5NOD3网友评论:2023热播 《用实例学习 Rust——所有权之“间接伤害”》等到第六层的时候,在这里终于感受不一样的气息,一团团属于地狱之塔的力量,在和那股奇异的力量相互僵持着,而在这个中间的地方,一个通天的白色石柱耸立在那里,在他的四周无数涟漪不断翻腾升起。