本文详细介绍Rust引用(reference)和借用(borrowing)特性。
引用 & 借用
引用(reference)
是 Rust 的特性:
&
符号表示引用
,允许程序引用某些值而不取得其所有权,类似于其他语言的指针,示例:&String
- 应用的变量在回收时,不会释放内存
- 应用的变量不能修改,否则报错:
cannot borrow *x as mutable, as it is behind a & reference
*
符号表示解引用
fn main() {
let str = String::from("hello str");
let len = len_fn(&str); // 引用 str,不发生 move,后面可以继续使用
println!("str = {}, len = {}", str, len)
}
fn len_fn(s: &String) -> usize {
s.len()
}
fn main() {
let mut str = String::from("hello str");
let len = len_fn(&mut str); // 引用 str,不发生 move,后面可以继续使用
println!("str = {}, len = {}", str, len)
}
fn len_fn(s: &mut String) -> usize {
s.push_str(", somethine...");
s.len()
}
- 可变引用的限制:在特定的作用域内,对某一块数据,只能有一个可变的引用,用于防止数据竞争(编译报错)
- 数据竞争会在以下三种情况下发生:
- 两个或多个指针同时访问同一个数据
- 至少有一个指针用于写入数据
- 没有使用任何机制来同步对数据的访问
- 不可以同时拥有一个可变引用和一个不可变引用,如:
let mut s = String::from("hello string"); let s1 = &s; let s2 = &s; let s3 = &mut s;
报错:cannot borrow s as mutable because it is also borrowed as immutable
- 可以同时有多个不可变引用
- 可以通过创建新的作用域,来允许非同时的创建多个可变引用
fn main() {
let mut str = String::from("hello str");
{
let s1: &mut String = &mut str;
}
let s2 = &mut str;
}
引用的规则
- 在任何时刻,只能满足以下条件之一:
- 引用必须一直有效
悬空引用(Dangling References)
悬空引用(Dangling References)
:一个指针引用了内存中的某个地址,而该块内存可能已经释放并分配给其他人使用。
在 Rust 里,编译器可以保证应用永远都不是悬空引用:如果引用了某些数据,编译器保证在引用离开作用域之前数据不会离开作用域。
示例:
fn main() {
let str = generate_str();
println!("{}", str)
}
fn generate_str() -> &String {
let s = String::from("hello string...");
&s
}
编译报错:
error[E0106]: missing lifetime specifier