定义
在Rust中,默认情况下所有的数据是不可变的,RefCell
作为Rust标准库中的一种智能指针类型,通过在运行时而非编译时执行借用检查,从而提供内部可变性,即在拥有不可变引用的同时允许对其中的数据进行修改。这在一定程度上打破了 Rust 的所有权和借用规则,使得在一些特定场景下编写更灵活和简洁的代码成为可能。
由于借用检查是在运行时进行的,会有一些额外的开销。因此在性能敏感的场景下,使用 RefCell
需要谨慎。
如果不小心违反了借用规则,程序会在运行时崩溃而不是在编译时发现错误。因此在使用 RefCell
时应尽量避免复杂的借用逻辑。
使用场景
复杂数据结构
实现树,图,链表等复杂数据结构时,多个节点间可能需要共享并修改同一个数据
#[derive(Debug)]
struct Node {
value: i32,
next: Option<Rc<RefCell<Node>>>,
}
use std::cell::RefCell;
fn main() {
let node1 = Rc::new(RefCell::new(Node { value: 1, next: None }));
let node2 = Rc::new(RefCell::new(Node { value: 2, next: Some(Rc::clone(&node1)) }));
let node3 = Rc::new(RefCell::new(Node { value: 3, next: Some(Rc::clone(&node1)) }));
println!("[before] Node1 value: {:?}", node1);
println!("[before] Node2 value: {:?}", node2);
println!("[before] Node3 value: {:?}", node3);
println!("****************************************");
node1.borrow_mut().value += 10;
println!("[after] Node1 value: {:?}", node1);
println!("[after] Node2 value: {:?}", node2);
println!("[after] Node3 value: {:?}", node3);
}
// 输出:
// [before] Node1 value: RefCell { value: Node { value: 1, next: None } }
// [before] Node2 value: RefCell { value: Node { value: 2, next: Some(RefCell { value: Node { value: 1, next: None } }) } }
// [before] Node3 value: RefCell { value: Node { value: 3, next: Some(RefCell { value: Node { value: 1, next: None } }) } }
// ****************************************
// [after] Node1 value: RefCell { value: Node { value: 11, next: None } }
// [after] Node2 value: RefCell { value: Node { value: 2, next: Some(RefCell { value: Node { value: 11, next: None } }) } }
// [after] Node3 value: RefCell { value: Node { value: 3, next: Some(RefCell { value: Node { value: 11, next: None } }) } }
单线程共享可变数据
非常适合需要在多个地方共享和修改数据的单线程环境中使用,且也只能在单线程环境中使用
use std::cell::RefCell;
fn main() {
let data = RefCell::new(5);
{
let mut data_ref = data.borrow_mut();
*data_ref += 1;
println!("Modified data: {}", data_ref); // 6
}
{
let data_ref = data.borrow();
println!("Data: {}", data_ref); // 6
}
}
当你想在不转移所有权的情况下借用某个值时,可以使用 borrow
方法
与Rc
结合使用
Rc
提供了不可变的多所有权,结合RefCell
可以提供对数据的可变共享
use std::cell::RefCell;
fn main() {
let data = Rc::new(RefCell::new(5));
let clone1 = Rc::clone(&data);
let clone2 = Rc::clone(&data);
{
let mut data_ref = clone1.borrow_mut();
*data_ref += 1;
}
{
let data_ref = clone2.borrow();
println!("Data: {}", data_ref); // 6
}
}