RefCell

Rust在编译阶段会进行严格的借用规则检查,规则如下:

  • 在任意给定时间,要么只能有一个可变引用,要么只能有多个不可变引用。
  • 引用必须总是有效。

即在编译阶段,当有一个不可变值时,不能可变的借用它。如下代码所示:

fn main() {
let x = 5;
let y = &mut x;
}

会产生编译错误:

error[E0596]: cannot borrow immutable local variable `x` as mutable
--> src/main.rs:32:18
|
31 | let x = 5;
| - consider changing this to `mut x`
32 | let y = &mut x;
| ^ cannot borrow mutably

但是在实际的编程场景中可能会需要在有不可变引用时改变数据的情况,这时可以考虑Rust中的内部可变性。其借用规则检查由编译期推迟到运行期。对应的,在编译期借用规则检查不通过,则会产生编译错误;而运行期借用规则检查不通过,则会panic,且有运行期的代价。

所以实际代码中使用RefCell<T>的情况是当你确定你的代码遵循借用规则,而编译器不能理解和确定的时候。代码仍然要符合借用规则,只不过规则检查放到了运行期。

RefCell代码实例1:

use std::cell::RefCell;

fn main() {
let x = RefCell::new(5u8);
assert_eq!(5, *x.borrow());
{
let mut y = x.borrow_mut();
*y = 10;
assert_eq!(10, *x.borrow());
let z = x.borrow(); //编译时会通过,但运行时panic!
}
}

运行结果:

thread 'main' panicked at 'already mutably borrowed: BorrowError', libcore/result.rs:983
:5
note: Run with `RUST_BACKTRACE=1` for a backtrace.

可以看到在运行时进行了借用检查,并且panic!

RefCell代码实例2:

#[derive(Debug, Default)]
struct Data {
a: u8,
b: RefCell<u8>,
} impl Data {
// 编译通过
pub fn value_b(&self) -> u8 {
let mut cache = self.b.borrow_mut();
if *cache != 0 {
return *cache;
}
*cache = 100;
*cache
} //编译错误:cannot mutably borrow field of immutable binding
pub fn value_a(&self) -> u8 {
if self.a != 0 {
return self.a;
} self.a = 100;
self.a
}
} fn main() {
let value = Data::default();
println!("{:?}", value);
value.value_b();
println!("{:?}", value);
}

value_a注释掉运行结果如下:

Data { a: 0, b: RefCell { value: 0 } }
Data { a: 0, b: RefCell { value: 100 } }

很多时候我们只能获取一个不可变引用,然而又需要改变所引用数据,这时用RefCell<T>是解决办法之一。

内部可变性

内部可变性(Interior mutability)是Rust中的一个设计模式,它允许你即使在有不可变引用时改变数据,这通常是借用规则所不允许的。为此,该模式在数据结构中使用unsafe代码来模糊Rust通常的可变性和借用规则。当可以确保代码在运行时会遵守借用规则,即使编译器不能保证的情况,可以选择使用那些运用内部可变性模式的类型。所涉及的 unsafe 代码将被封装进安全的 API 中,而外部类型仍然是不可变的。

Rust中的RefCell和内部可变性的更多相关文章

  1. 【译】理解Rust中的Futures (一)

    原文标题:Understanding Futures In Rust -- Part 1 原文链接:https://www.viget.com/articles/understanding-futur ...

  2. 【译】Rust中的array、vector和slice

    原文链接:https://hashrust.com/blog/arrays-vectors-and-slices-in-rust/ 原文标题:Arrays, vectors and slices in ...

  3. 【译】理解Rust中的闭包

    原文标题:Understanding Closures in Rust 原文链接:https://medium.com/swlh/understanding-closures-in-rust-21f2 ...

  4. 【译】理解Rust中的Futures(二)

    原文标题:Understanding Futures in Rust -- Part 2 原文链接:https://www.viget.com/articles/understanding-futur ...

  5. 【译】深入理解Rust中的生命周期

    原文标题:Understanding Rust Lifetimes 原文链接:https://medium.com/nearprotocol/understanding-rust-lifetimes- ...

  6. Rust 中的继承与代码复用

    在学习Rust过程中突然想到怎么实现继承,特别是用于代码复用的继承,于是在网上查了查,发现不是那么简单的. C++的继承 首先看看c++中是如何做的. 例如要做一个场景结点的Node类和一个Sprit ...

  7. Rust 中的类型转换

    1. as 运算符 as 运算符有点像 C 中的强制类型转换,区别在于,它只能用于原始类型(i32 .i64 .f32 . f64 . u8 . u32 . char 等类型),并且它是安全的. 例 ...

  8. Rust中的Slices

    这个slice切片,python中有,go中有, 但确实,Rust中最严格. 精彩见如下URL: Rust 程序设计语言(第二版) 简体中文版 · GitBook (Legacy) https://k ...

  9. 刷完欧拉计划中难度系数为5%的所有63道题,我学会了Rust中的哪些知识点?

    我为什么学Rust? 2019年6月18日,Facebook发布了数字货币Libra的技术白皮书,我也第一时间体验了一下它的智能合约编程语言MOVE,发现这个MOVE是用Rust编写的,看来想准确理解 ...

随机推荐

  1. 认识JVM的内存分配

    当我们在JVM中运行一段程序代码,JVM初始运行的时候都会分配好Method Area(方法区)和Heap(堆),而JVM每遇到一个线程,就为其分配一个Program Counter Register ...

  2. Pycharm 专业版激活码(转) 有效期到2020/06月

    亲测有效!!! 有效期截止为2020年06月,多谢大家支持与讨论! K6IXATEF43-eyJsaWNlbnNlSWQiOiJLNklYQVRFRjQzIiwibGljZW5zZWVOYW1lIjo ...

  3. Spring Cloud gateway 三 自定义过滤器GatewayFilter

    之前zuul 网关介绍.他有过滤器周期是四种,也是四种类型的过滤器.而gateway 只有俩种过滤器:"pre" 和 "post". PRE: 这种过滤器在请求 ...

  4. 基于 Jenkins Pipeline 自动化部署

    最近在公司推行Docker Swarm集群的过程中,需要用到Jenkins来做自动化部署,Jenkins实现自动化部署有很多种方案,可以直接在jenkins页面写Job,把一些操作和脚本都通过页面设置 ...

  5. Android DisplayMetrics 获取和屏幕相关的信息

    Android源码中是这样来描述DisplayMetrics的. /** * A structure describing general information about a display, s ...

  6. 详解Spring Security的HttpBasic登录验证模式

    一.HttpBasic模式的应用场景 HttpBasic登录验证模式是Spring Security实现登录验证最简单的一种方式,也可以说是最简陋的一种方式.它的目的并不是保障登录验证的绝对安全,而是 ...

  7. 过滤广告(只能发布 [a-zA-z0-9及汉字,;?.]) ,排除其他特殊符号

      /** * 过滤广告(只能发布 [a-zA-z0-9及汉字,;?.]) ,排除其他特殊符号 * Created by 1 on 2015/8/19. */ public class FilterA ...

  8. Deepin 下 使用 Rider 开发 .NET Core

    Deepin 下 使用 Rider 开发 .NET Core 国产的 Deepin 不错,安利一下. Deepin 用了也有一两年,也只是玩玩,没用在开发上面.后来 Win10 不太清真了,就想着能不 ...

  9. 深入理解计算机系统 第二章 信息的表示和处理 part1

    欣哥划的重点: 第二章比较难,建议至少掌握下面几个知识点: 1. 字节顺序 : 大端和小端 2. 运行 图2-24, 图2-25程序 show-bytes.c 观察结果,看看有什么问题 3. 理解布尔 ...

  10. JDBD连接MySQL中的驱动与时区问题

    1.在进行jdbc与mysql连接的时候应注意,加载驱动的方式根据MySQL版本内容来说 有变化 5.7版本之前: String driver= "com.mysql.jdbc.Driver ...