在 Rust 中,每个值都有一个变量作为它的所有者。当这个变量离开其作用域时,该值将被丢弃。然而,我们经常需要多个指向同一数据的引用,或者希望在函数调用中传递大型数据结构而不复制它。这就是 Rust 中的引用与借用发挥作用的地方。
什么是引用?
引用是指向某个值的指针,但与 C/C++ 中的指针不同,Rust 中的引用是安全的,不会造成空指针或者悬垂指针。在 Rust 中,引用使用 &
符号标识。例如:
let x = 5;
let y = &x; // y is a reference to x
什么是借用?
当我们将一个值的引用传递给函数或方法时,我们说这个操作发生了借用。在 Rust 中,默认情况下,对于不可变引用(&T
),你可以创建多个引用,但是对于可变引用(&mut T
),你只能有一个。这样做的原因是为了防止数据竞争和悬垂指针。例如:
fn print_value(v: &i32) { // v is a borrowed reference to an i32
println!("{}", v);
}
let x = 5;
print_value(&x); // we're borrowing x, so we can still use it afterwards
可变与不可变引用的规则
在 Rust 中,对于同一数据,你只能有一个可变引用或者任意数量的不可变引用。这是为了防止数据竞争和悬垂指针。例如:
let mut x = 5;
let y = &mut x; // this is ok, we have only one mutable reference to x
let z = &x; // this would be an error: cannot borrow `x` as immutable because it is also borrowed as mutable
生命周期
在 Rust 中,每个引用都有一个生命周期(lifetime),表示该引用保持有效的作用域。编译器使用借用检查器来确保这些生命周期是正确的,从而防止悬垂指针和数据竞争。例如:
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { // 'a is the lifetime of the returned reference
if x.len() > y.len() {
x
} else {
y
}
}
结论
Rust 中的引用与借用是一项强大而安全的功能,可以帮助你编写无数据竞争和悬垂指针的代码。通过遵循 Rust 中关于引用和生命周期的规则,你可以在保持性能的同时编写安全且正确的代码。