0
点赞
收藏
分享

微信扫一扫

rust 结合 Rc<T> 和 RefCell<T> 来拥有多个可变数据所有者

RefCell<T> 的一个常见用法是与 Rc<T> 结合。回忆一下 Rc<T> 允许对相同数据有多个所有者,不过只

能提供数据的不可变访问。如果有一个储存了 RefCell<T> 的 Rc<T> 的话,就可以得到有多个所有者 并

且可以修改的值了!

例如,回忆示例 15-18 的 cons list 的例子中使用 Rc<T> 使得多个列表共享另一个列表的所有权。因为

Rc<T> 只存放不可变值,所以一旦创建了这些列表值后就不能修改。让我们加入 RefCell<T> 来获得修改

列表中值的能力。示例 15-24 展示了通过在 Cons 定义中使用 RefCell<T>,我们就允许修改所有列表中

的值了:

文件名: src∕main.rs

#[derive(Debug)]

enum List {

Cons(Rc<RefCell<i32>>, Rc<List>),

Nil,

}

use crate::List::{Cons, Nil};

use std::cell::RefCell;

use std::rc::Rc;

fn main() {

let value = Rc::new(RefCell::new(5));

let a = Rc::new(Cons(Rc::clone(&value), Rc::new(Nil)));

let b = Cons(Rc::new(RefCell::new(3)), Rc::clone(&a));

let c = Cons(Rc::new(RefCell::new(4)), Rc::clone(&a));

*value.borrow_mut() += 10;

println!("a after = {:?}", a);

println!("b after = {:?}", b);

println!("c after = {:?}", c);

}

示例 15-24:使用 Rc<RefCell<i32>> 创建可以修改的 List

这里创建了一个 Rc<RefCell<i32>> 实例并储存在变量 value 中以便之后直接访问。接着在 a 中用包含

value 的 Cons 成员创建了一个 List。需要克隆 value 以便 a 和 value 都能拥有其内部值 5 的所有权,而

不是将所有权从 value 移动到 a 或者让 a 借用 value。

我们将列表 a 封装进了 Rc<T> 这样当创建列表 b 和 c 时,他们都可以引用 a,正如示例 15-18 一样。

一旦创建了列表 a、b 和 c,我们将 value 的值加 10。为此对 value 调用了 borrow_mut,这里使用了第

五章讨论的自动解引用功能(”−> 运算符到哪去了?” 部分)来解引用 Rc<T> 以获取其内部的 RefCell<T>

值。borrow_mut 方法返回 RefMut<T> 智能指针,可以对其使用解引用运算符并修改其内部值。

当我们打印出 a、b 和 c 时,可以看到他们都拥有修改后的值 15 而不是 5:

$ cargo run

Compiling cons-list v0.1.0 (file:///projects/cons-list)

Finished dev [unoptimized + debuginfo] target(s) in 0.63s

Running `target/debug/cons-list`

a after = Cons(RefCell { value: 15 }, Nil)

b after = Cons(RefCell { value: 3 }, Cons(RefCell { value: 15 }, Nil))

c after = Cons(RefCell { value: 4 }, Cons(RefCell { value: 15 }, Nil))

这是非常巧妙的!通过使用 RefCell<T>,我们可以拥有一个表面上不可变的 List,不过可以使用

RefCell<T> 中提供内部可变性的方法来在需要时修改数据。RefCell<T> 的运行时借用规则检查也确实保

护我们免于出现数据竞争——有时为了数据结构的灵活性而付出一些性能是值得的。

标准库中也有其他提供内部可变性的类型,比如 Cell<T>,它类似 RefCell<T> 但有一点除外:它并

非提供内部值的引用,而是把值拷贝进和拷贝出 Cell<T>。还有 Mutex<T>,其提供线程间安全的内

部可变性,我们将在第 16 章中讨论其用法。请查看标准库来获取更多细节关于这些不同类型之间的区别。

举报

相关推荐

0 条评论