从C++的RAII到Rust的所有权(二)
Contact me
- Blog -> https://cugtyt.github.io/blog/index
- Email -> cugtyt@qq.com
- GitHub -> Cugtyt@GitHub
上次我们说到两种对象传递方法:复制和移动[引用],默认变量是不变的,对象只有一个引用,听起来是个非常纯粹的做法,但是相比我们一般的做法有些束手束脚,这样有什么好处呢?
数据竞争(data race)是一种特定类型的竞争状态,它可由这三个行为造成:
- 两个或更多指针同时访问同一数据。
- 至少有一个这样的指针被用来写入数据。
- 不存在同步数据访问的机制。
来自《Rust程序设计语言》
Rust天生的不存在这个问题,这些问题在编译时就会被发现。
但是故事还没有结束,我们要获取对象的一部分怎么办?
// 获取第一个单词
fn first_word(s: &String) -> &str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}
&s[..]
}
fn main() {
let mut s = String::from("hello world");
let word = first_word(&s);
s.clear(); // Error!
}
所有者清空了,我们获得的对象部分也无效了,所以这个是不能编译的,所以一个规则是一个时间内不能可变和不可变引用同时存在。
- 在任意给定时间,只能拥有如下中的一个:
- 一个可变引用
- 任意数量的不可变引用
- 引用必须总是有效的
来自《Rust程序设计语言》
这样我们保证了在需要变的时候,只有一个变化者,不变的时候,多少不可变都是无害的。
回想一下C++,我们默认是可变的,所以很容易出现数据竞争,多线程下需要小心。
似乎已经说完了,但是引用有个麻烦的特性,不知道你注意到没有那就是我们眼皮子底下的:引用必须总是有效的。有时候我们不能这样保证,比如我们要实现链表,我们不能第一步就确定好节点的下一个节点是啥,所以类似一系列原因,Rust还是引入了指针,指针又回来了!!
哈哈,并没有变得简单,只不过这些语言特性在内存管理,垃圾回收等方面提供了很大便利,Rust的指针是个什么鬼,和C++的指针一样吗,我们后续再聊。