转载

Rust 学习笔记(十二) -- 各种容器和指针之Cell和RefCell | 神佑之园

Rust 学习笔记(十二) -- 各种容器和指针之Cell和RefCell | 神佑之园

Cell和RefCell代表了Rust的一个特性:Interior Mutability,内在的可变性。

顾名思义,Cell就是一个细胞,一个单元,或者说一个容器。这个容器和Box不同,Box是一个不可变的指针,如果我们想改变一个box的值,比如这么搞:

fn main() {    let mut x = Box::new(10i32);    *x = 20;    println!("{:?}", x);  }  

结果会打印出来20,我们无法在不dereference的情况下修改Box里面的值,并且如果要修改的话,必须要用let mut来定义Box的绑定变量。

而使用let mut有很多不方便,因为Rust的一条铁律就是可变修改只能有一个,没有还回来之前根本不能继续修改。所以cell和refcell的存在就有了必要,我们先看cell的特点:

use std::cell::Cell;  fn main() {    let x = Cell::new(20i32);    let y = &x;    let z = &x;    y.set(40i32);    println!("{:?}", x);    z.set(80i32);    println!("{:?}", x);   } 

打印出来的结果是:

Cell { value: 40 } Cell { value: 80 } 

是不是很神奇?y和z都是x的不可变调用,但是都成功的修改了x的值。这就是Rust在不破坏其核心安全性的前提下,对易用性作出的妥协,让我们可以在在同一个scope里面,让一个变量可以被一个或者数个不可变借用修改。

这个其实有点类似python的tuple内置list的情况,我们知道python里面tuple是immutable的,list是mutable的,于是我们可以有这样的代码:

x = ([1, 2], [3, 4]) x[0].append(5) print(x) 

我们得到了([1,2,5], [3,4]). 虽然实现机理上Rust和Python区别很大,但是interior mutability的意思,基本上就是上面这个List的tuple所描述的。

Rust的Cell是很方便,但是问题在于不是每个类型都可以用Cell包起来。Rust的文档说的明白,只有实现了copy属性的类型才能够用cell包裹,一般来说,我们自己定义的struct和trait都是没有copy属性的,所以这种就只能用RefCell。

顾名思义,RefCell是引用单元。这个的限制就更多了:没有了威武霸气的set方法,取而代之的是borrow和borrow_mut,看名字也看得出来就是可读借用和可变借用。注意这里rust的文档特别强调了,依然需要满足可变借用的唯一性,甚至更加严格:如果存在可变借用,那么在该可变借用的作用域结束之前,那么即便是再次进行只读借用,编译器都会报错,比如下面这个代码就无法通过编译:

use std::cell::RefCell;  fn main() {    let x = RefCell::new(20i32);     let y = x.borrow_mut();    let z = x.borrow();  }  

看到这里可能会非常灰心失望,这么严格的限制,要RefCell何用?当然是有用的,因为RefCell的限制只是针对一个变量的,我们可以非常轻易的绕过这个限制:

use std::cell::RefCell;  fn main() {    let x = RefCell::new(20i32);       let z = &x;     let y = &x;       *z.borrow_mut() = 10;      println!("{:?}", x);    *y.borrow_mut() = 30;    println!("{:?}", x);   } 

系统输出

RefCell { value: 10 } RefCell { value: 30 }  

所以我们可以通过其他的只读绑定的borrow_mut来修改值,然后用最初的Refcell负责输出。当然如果要抬杠,说我就是想用一个变量,同时存在多个mutable的borrow怎么办?Rust自然也有办法,在下一节rc里面会继续说这个问题.

原文  https://www.scislab.com/zh-hans/blog/rust-xue-xi-bi-ji-shi-er-ge-chong-rong-qi-he-zhi-zhen-zhi-cellhe-refcell/
正文到此结束
Loading...