本文概述
- 内部可变性
- 使用RefCell < T> 在运行时跟踪借阅
- 通过组合Rc < T> 和RefCell < T> 的可变数据的多个所有者
要记住的要点:
- RefCell < T> 表示对其拥有的数据的单一所有权。
- 如果我们使用RefCell < T> , 则在运行时强制执行不变式。
- RefCell < T> 主要用于单线程方案, 如果在多线程情况下使用, 将给出错误。
- RefCell < T> 在运行时检查可变借位。因此, 可以说即使RefCell < T> 值是不可变的, 我们也可以对其进行突变。
让我们看一个简单的例子:
fn main(){let a = 15;
let b = &
mut a;
}
输出
文章图片
在上面的示例中, 我们看到不可变值不能可变地借用。但是, RefCell是实现内部可变性的一种方法。
使用RefCell < T> 在运行时跟踪借入 RefCell < T> 由两个在运行时跟踪借用的方法组成:
- 借款():借款()方法返回类型为Ref < T> 的智能指针。
- 借用_mut():借用_mut()方法返回类型为RefMut < < T> 的智能指针。
- RefCell < T> 记录当前有多少Ref < T> 和Refmut < T> 智能指针处于活动状态。
- 每当调用rowe()方法时, RefCell < T> 都会增加活动的不可变借位的数量。当Rc < T> 超出范围时, RefCell < T> 会将计数减少一。
- RefCell < T> 使我们有许多不可变的借项, 但一次只有一个可变的借项, 就像编译时的借用规则一样。如果我们违反此规则, 则RefCell < T> 将在运行时惊慌。
借款()方法借用不可变值。可以同时进行多次不可变借用。
句法:
pub fn borrow(&
self) ->
Ref<
T>
让我们看一个发生多个不可变借位的简单示例:
use std::cell::RefCell;
fn main(){let a = RefCell::new(15);
let b = a.borrow();
let c = a.borrow();
println!("Value of b is : {}", b);
println!("Value of c is : {}", c);
}
输出
文章图片
让我们看一个紧急情况的简单例子:
use std::cell::RefCell;
fn main(){let a = RefCell::new(10);
let b = a.borrow();
let c = a.borrow_mut();
// cause panic.println!("Value of b is : {}", b);
println!("Value of c is : {}", c);
}
输出
文章图片
在上面的示例中, 程序在运行时由于不可变借项和可变借项而出现紧急情况, 不能同时发生。
loan_mut()方法
借款的方法mutable_value。可变借用只能发生一次。
句法:
pub fn borrow_mut(&
self) ->
RefMut<
T>
;
让我们看一个简单的例子:
use std::cell::RefCell;
fn main(){let a = RefCell::new(15);
let b = a.borrow_mut();
println!("Now, value of b is {}", b);
}
文章图片
让我们看一个紧急情况的简单例子:
use std::cell::RefCell;
fn main(){let a = RefCell::new(15);
let b = a.borrow_mut();
let c = a.borrow_mut();
}
输出
文章图片
在上面的示例中, 可变借贷发生了两次。因此, 程序在运行时出现紧急情况, 并引发错误” 已借用:BorrowMutError” 。
通过组合Rc < T> 和RefCell < T> 的可变数据的多个所有者 我们可以结合使用Rc < T> 和RefCell < T> , 以便我们可以拥有可变数据的多个所有者。 Rc < T> 允许你有一个数据的多个所有者, 但它仅提供对数据的不变访问。 RefCell < T> 使你可以对数据进行突变。因此, 可以说Rc < T> 和RefCell < T> 的组合提供了具有可变数据的多个所有者的灵活性。
让我们看一个简单的例子:
#[derive(Debug)]enum List{ Cons(Rc<
RefCell<
String>
>
, Rc<
List>
), Nil, }use List:: {Cons, Nil};
use std::rc::Rc;
use std::cell::RefCell;
fn main(){let val = Rc::new(RefCell::new(String::from("java")));
let a = Rc::new(Cons(Rc::clone(&
val), Rc::new(Nil)));
let b = Cons(Rc::new(RefCell::new(String::from("C"))), Rc::clone(&
a));
let c = Cons(Rc::new(RefCell::new(String::from("C++"))), Rc::clone(&
a));
*val.borrow_mut() = String::from("C# language");
println!("value of a is : {:?}", a);
println!("value of b is : {:?}", b);
println!("value of c is : {:?}", c);
}
输出
文章图片
【Rust RefCell T用法详细示例】在上面的示例中, 我们创建了一个变量” val” , 并将值” java” 存储到变量” val” 中。然后, 我们创建列表” a” , 并克隆” val” 变量, 以便变量” a” 和” val” 都具有” java” 值的所有权, 而不是将所有权从” val” 转移到” a” 变量。创建” a” 列表后, 我们创建” b” 和” c” 列表并克隆” a” 列表。创建列表之后, 通过使用rowe_mut()方法, 将” val” 变量的值替换为” C#” 语言” 。
推荐阅读
- Rust智能指针解析
- Rust特质trait用法介绍
- Rust泛型图解和用法
- Rust生命周期详细图解
- Rust RC T用法解析
- Rust Box T用法
- Rust删除特质trait实例分析
- Rust Deref T解析和用法
- Rust可恢复错误处理实例分析