Rust-智能指针:RefCell<T>和内部可变性模式
内部可变性 (Interior mutability) 是Rust中的一个设计模式,它允许你即使在有不可变引用时也可以改变数据,这通常是借用规则不允许的。为了改变数据,该模式在数据结构中使用 unsafe 代码来模糊Rust通常的可变性和借用规则。
通过RefCell<T>在运行时检查借用规则
不同于Rc<T>,RefCell<T>代表其数据的唯一的所有权。那么是什么让RefCell<T>不同于像Box<T>这样的类型呢?我们回想一下借用规则:
- 在任意给定时该,只能拥有一个可变引用或任意数量的不可变引用之一(而不是两者)。
- 引用必须总是有效的。
对于引用和Box<T>,借用规则的不可变性用于编译时。对于RefCell<T>,这些不可变性作用于运行时。对于引用,如果违反这些规则,会得到一个编译错误。而对于RefCell<T>,如果违反这些规则程序会panic并退出。
因为一些分析是不可能的,如果Rust编译器不能通过所有权规则编译,它可能会拒绝一个正确的程序。如果Rust接受不正确的程序,虽然会给程序带来不便,但不会带来灾难。RefCell<T>正是用于当你确信代码遵守借用规则,而编译器不能理解和确定的时候。
类似于Rc<T>,RefCell<T>只能用于单线程场景。
如下为选择Box<T>,Rc<T>或RefCell<T>的理由:
- Rc<T>允许相同数据有多个所有者;Box<T>和RefCell<T>有单一所有者。
- Box<T>允许在编译时执行不可变或可变借用检查;Rc<T>仅允许在编译时执行不可变借用检查;RefCell<T>允许在运行时执行不可变或可变借用检查。
- 因为RefCell<T>允许在运行时执行可变借用检查,所以我们可以在即便RefCell<T>自身是不可变的情况下修改其内部的值。
在不可变值内部改变值就是内部可变性模式。让我们看看何时内部可变性是有用的。
内部可变性:不可变值的可变借用
借用规则的一个推论是当有一个不可变值时,不能可变地借用它。如下代码不能编译:
let x = 5;
let y = &mut x;
有以下错误:
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> src/main.rs:41:13 | 40 | let x = 5; | - help: consider changing this to be mutable: `mut x` 41 | let y = &mut x; | ^^^^^^ cannot borrow as mutable
然而,特定情况下,令一个值在其方法内部能够修改自身,而在其它代码中仍视为不可变,是很有用的。值方法外部的代码就不能修改其值。
RefCell<T>是一个获得内部可变性的方法。RefCell<T>并没有完全绕开借用规则,编译器中的借用检查器允许内部可变性并相应地在运行时检查借用规则。如违反了这些规则,会出现panic而不是编译错误。
内部可变性的用例:mock对象
测试替身(test double)是一个通用编程概念,它代表一个在测试中替代某个类型的类型。mock对象是特定类型的测试替身,它们记录测试过程中发生了什么以便可以断言操作是正确的。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)
2020-09-30 684. Redundant Connection (BFS)
2019-09-30 QuickSort