这是我参与11月更文挑战的第25天,活动详情查看:2021最后一次更文挑战
可变引用
在上一篇文章中,我们提到了借用的概念,将获取引用作为函数参数称为 借用(borrowing),通常情况下,我们无法修改借来的变量
,但是可以通过可变引用实现修改借来的变量
。代码示例如下:
1 | rust复制代码fn main() { |
要想实现修改借来的变量
就必须将 s
改为 mut
。然后必须创建一个可变引用 &mut s
和接受一个可变引用 some_string: &mut String
。
但是可变引用有一个很大的限制:在特定作用域中的特定数据只能有一个可变引用。比如下述代码就不会被成功编译。
1 | rust复制代码fn main() { |
编译运行就会抛出如下异常:
1 | ini复制代码error[E0499]: cannot borrow `s` as mutable more than once at a time |
所以这种修改借来的变量
的可变引用是以一种受限制的方式允许修改,这个限制的好处是 Rust 可以在编译时就避免数据竞争。数据竞争(data race)类似于竞态条件,它可由这三个行为造成:
- 两个或更多指针同时访问同一数据。
- 至少有一个指针被用来写入数据。
- 没有同步数据访问的机制。
数据竞争会导致未定义行为,难以在运行时追踪,并且难以诊断和修复;Rust 避免了这种情况的发生。我们可以使用{}
创建一个新的作用域,这样就能够允许多个可变引用了,只是不能在同一个作用域中同时拥有:
1 | rust复制代码fn main() { |
另外还需要注意的是,不能在拥有不可变引用的同时拥有可变引用。不可变引用的用户可不希望在他们的眼皮底下值就被意外的改变了!但是多个不可变引用是可以的,因为没有哪个只能读取数据的人有能力影响其他人读取到的数据。如下述代码:
1 | rust复制代码fn main() { |
上面代码示例编译时会抛出如下异常:
1 | rust复制代码error[E0502]: cannot borrow `s` as mutable because it is also borrowed as immutable |
但是如果可变引用和不可变引用他们的作用域不重叠代码就是可以编译的,我们可以将上面的代码示例进行修改就可以正常运行了。
1 | rust复制代码fn main() { |
悬垂引用(Dangling References)
在具有指针的语言中,很容易通过释放内存时保留指向它的指针而错误地生成一个 悬垂指针(dangling pointer),所谓悬垂指针是其指向的内存可能已经被分配给其它持有者。相比之下,在 Rust 中编译器确保引用永远也不会变成悬垂状态:当你拥有一些数据的引用,编译器确保数据不会在其引用之前离开作用域。
当我们不小心创建了悬垂引用,Rust在编译的时候就会抛出异常:
1 | rust复制代码fn main() { |
因为 s
是在 dangle
函数内创建的,当 dangle
的代码执行完毕后,s
将被释放。不过我们尝试返回它的引用。这意味着这个引用会指向一个无效的 String
,所以在编译时Rust就会抛出异常,解决方式就是直接返回String
。
1 | rust复制代码fn no_dangle() -> String { |
结语
文章首发于微信公众号程序媛小庄,同步于掘金。
码字不易,转载请说明出处,走过路过的小伙伴们伸出可爱的小指头点个赞再走吧(╹▽╹)
本文转载自: 掘金