- Published on
🦀 从 Rust 的引用看计算机的内存和数据安全
- Authors
- Name
- 阿森 Hansen
- 阅读对象:计算机工程师,rust 程序员或爱好者
- 预备知识:竞态条件和锁的基础知识,rust 中关于生命周期和引用与借用的基础知识
TL;DR 变量访问的三板斧
Rust 中访问变量有三种方式:
- 捕获所有权后访问
- 使用不可变引用访问
- 使用可变引用访问
1 安全而高效的 Rust
Rust 是一个讲究安全和高效的语言,我使用了 Rust 一段时间之后,逐渐领悟了 Rust 的作者对“安全”的理解。
对于 Rust 的初学者来说,最难的两道坎莫过于**“生命周期”和“所有权”**这两个概念。这也是 Rust 语言最具特色最核心的概念,也正是它们保证了语言的安全和高效。
这篇文章写一写我自己对 Rust 所有权的理解。
2 Rust 的所有权
Rust 对变量维护所有权并管理它的引用,来保证内存安全。
Rust 的变量声明非常简单:
let test_str = String::from("foobar");
这个语句做了三件事:
- 在内存中开辟一段空间。
- 将“foobar”字符串写入这段内存。
- 将该内存的所有权绑定到
test_str
变量
使用这个变量有三种方式:
// 1. 将字符串复制到新的内存空间
// 此时 test_str_copy 有了独立的所有权
let test_str_copy = test_str.clone();
// 2. 新建一个不可变引用(只读)
let test_str_ref = &test_str;
// 3. 创建一个可变引用(读写)
let test_str_mut_ref = &mut test_str;
以上方法是如何保证内存安全的呢?两个方面:
- 一旦有个变量具有可变引用,那么这个变量的内存就无法在其他地方读写,从而保证了排他性。
- 如果一个变量具有不可变引用,那么就无法再被“可变引用”了,保证了在读内存的时候,值不会改变。
3 数据库的属性锁
Rust 所有权机制让我想到了另外一个概念:属性锁。
属性锁在数据库和高并发编程里很常见。例如在数据库的事务管理中存在两种属性锁:
- 共享锁(读锁):当一个事务对一个数据加上共享锁后,这个数据就不能被其他事务修改,但是其他的事务依然可以读该数据。也就是说,共享锁一个数据可以有多个,大家都可以读。
- 排他锁(写锁):当一个事务要写一个数据时,会加排他锁,其他事务无法读或写这段数据。排他锁一个数据只能有一个,只有一个事务可以读写。
数据库中的“共享锁”和“排他锁”刚好对应了“不可变引用”和“可变引用”。
4 打个比方……
如果把 Rust 的一个变量或者数据库的一段数据比作一个妹子。
不可变引用就好比是单身的妹子,男孩子们都可以追。姑娘相当于被上了一个“共享锁”,大家都能和姑娘聊聊天但是不能动手。
可变引用就好像是已经有男朋友的妹子,像上了一把“排他锁”,只有她的男朋友可以牵手,其他男生都不能追求。
这样解释是不是形象了跟多?😂
5 总结:计算机的内存安全
人类的大脑一次只能处理一件事,而计算机不一样,它可以并行处理很多事。就好像多重人格,计算机工程师必须想办法管理好计算机的“多重人格”,让他们能和谐相处。
当多重人格之间打架了,计算机程序就可能出错。为了保证不出错,工程师们会用“锁”来控制“多重人格”,让他们好好协作不出乱子。
这篇文章,我们看到了 Rust 用 “所有权” 来保证内存安全,而数据库用“属性锁”来实现表的数据安全。他们背后的原理和逻辑其实是一样的:让并行处理的过程有序而正确。
参考
This work is licensed under Creative Commons Attribution-NonCommercial 4.0 International