Mutability
在Rust中,如果我们这样操作一个变量:
1 | let x = 5; |
我们就会得到一个编译错误。
如果要更改一个变量,我们需要添加mut
关键字:
1 | let mut x = 5; |
我们也可以像下面一样更改一个变量的值:
1 | let mut x = 5; |
注意到y
是可变变量x
的可变引用,所以我们可以y
来更改x
的值,但是我们并不能更改y
,在这里只有x
是可变的。
Interior Mutability & Exterior Mutability
考虑下面一个例子:
1 | use std::sync::Arc; |
当clone
函数被调用后,Arc<T>
会增加它的引用计数,这咋一看和x
是不可变的变量矛盾了不是吗?在这里,Arc<T>
暴露在用户面前的是不可变的,但是其内部却是可以改变的,因为它使用了RefCell
。标准库对Cell
和RefCell
的定义如下:
1 | Values of the Cell<T> and RefCell<T> types may be mutated through shared references (i.e. the common &T type), whereas most Rust types can only be mutated through unique (&mut T) references. We say that Cell<T> and RefCell<T> provide 'interior mutability', in contrast with typical Rust types that exhibit 'inherited mutability'. |
也就是说我们可以像这样操作变量:
1 | use std::cell::RefCell; |
borrow_mut
将变量内部的可变借给了用户,这样我们就可以修改x
的值了。还记得Rust的借用规则吗?我们说Rust的一个变量可以有多个不可变的借用,但是有且仅有一个可变的借用,所以如果我们这样操作:
1 | use std::cell::RefCell; |
那么这段代码就会在运行时崩溃(panic in runtime),这也说明了一点:RefCell
在运行时执行了Rust的借用规则。
RefCell
和Cell
的区别在于,Cell
只能用于那么实现了Copy
Trait的类型,其余的类型使用RefCell
,RefCell
让程序在修改变量时必须先获得一个写锁。
Cell和RefCell的运用
如果我们自定义了一个变量,变量的某些属性是可以修改的,而某些属性不能修改,那么这个时候就可以用Cell
或者RefCell
了:
1 | use std::cell::Cell; |