4.9 KiB
References and Borrowing
传递引用可以使其他变量拥有数据,而不获得值的所有权。引用类似于指针,根据地址来访问值,引用保证了在该引用的生命周期内指向特定类型的有效值。
引用图示: (与使用引用相反的&
是取消引用,这是通过取消引用运算符完成的*
)
fn calculate_length(s: &String) -> usize { // s is a reference to a String
s.len()
} // Here, s goes out of scope. But because it does not have ownership of what
// it refers to, it is not dropped.
变量s
有效的范围与任何函数参数的范围相同,但引用指向的值在s
停止使用时不会被删除,因为s
没有所有权。当函数将引用作为参数而不是实际值时,我们不需要返回值来归还所有权,因为我们从来没有所有权。 usize表示无符号整数、值的范围取决于系统架构(32位或64位)
正如默认情况下变量是不可变的一样,引用也是如此,未加mut就不可改变。
可变引用
一个值的可变引用同一时间只能有一个(必须等第一个借用者使用完才行,类似于单个可变引用)。
因为我们不能在同一时间多次可变借用 s。第一个可变借用在 r1 中,必须持续到在 println! 中使用它之后,但在创建那个可变引用并使用它之间,我们尝试创建另一个可变引用 r2,该引用借用了与 r1 相同的数据。
类似于单个可变引用:
限制防止同时对相同数据进行多次可变引用,允许在非常受控的方式下进行mut。这是新 Rustaceans 难以应对的,因为大多数语言都允许您在需要时进行mut。这种限制的好处在于,Rust 可以在编译时防止数据竞争。数据竞争类似于竞争条件,当出现以下三种行为时会发生:
-
两个或更多指针同时访问相同的数据。
-
至少有一个指针用于写入数据。
-
没有同步访问数据的机制。
数据竞争导致未定义行为,在运行时跟踪它们时很难诊断和修复;Rust 通过拒绝编译具有数据竞争的代码来防止这个问题!
多个可变引用(不同时)
新增范围,类似于上面的代码,但是更直观。
可变引用与不可变引用
可变引用允许在引用的数据上修改数据,而不可变引用则不允许。
在 Rust 中,如果要修改一个变量,则需要使用可变引用。而如果只是希望读取一个变量的值,而不希望修改它,则可以使用不可变引用。
类似与上面,在最后一次使用之后(范围不重叠),运行使用,建议加括号。编译器可以判断在范围结束之前的某个点不再使用该引用。
加上括号的版本(更直观)!
悬挂引用
在有指针的语言中,很容易通过在保留指向内存的指针的同时释放某些内存来错误地创建一个悬挂指针(即指向可能已给其他人的内存位置的指针)。相比之下,Rust 可以保证引用永远不会是悬挂引用:如果你对某些数据有一个引用,编译器会确保数据在引用数据之前不会离开作用域。
引用没有所有权,一下案例赶回的是借用,而真正的所有权仍在s上,而s在离开作用域后就已经被丢弃。因此以下代码是无效的!
正确的方法是直接移动所有权!