面试题答案
一键面试Rust内存模型中所有权的核心概念
- 所有权:在Rust中,每一个值都有一个变量作为其所有者。在同一时刻,一个值只能有一个所有者。当所有者超出其作用域时,该值将被释放。
- 移动(Move):当一个值被赋予另一个变量,或者作为参数传递给函数时,所有权会发生移动。这意味着原来的变量不再拥有该值的所有权,新的变量成为所有者。
- 借用(Borrowing):允许在不转移所有权的情况下访问值。分为不可变借用(使用
&
符号)和可变借用(使用&mut
符号)。但有一个规则,在同一作用域内,要么只能有一个可变借用,要么可以有多个不可变借用,不能同时存在可变借用和不可变借用。 - 生命周期:描述了引用保持有效的作用域。编译器会通过生命周期检查来确保引用在其生命周期内始终有效。
实际编程中利用所有权机制避免内存泄漏和悬空指针问题的示例
fn main() {
// 避免内存泄漏
let s1 = String::from("hello");
// s1 拥有这个字符串的所有权
let s2 = s1;
// s1 的所有权移动到 s2,此时 s1 不再有效,避免了内存泄漏,因为 Rust 会在 s2 超出作用域时释放内存
// 避免悬空指针
let mut s3 = String::from("world");
let r1 = &s3;
// r1 是对 s3 的不可变借用
// 这里不能对 s3 进行修改,因为有不可变借用 r1 存在
println!("{}", r1);
let r2 = &mut s3;
// r2 是对 s3 的可变借用
// 此时不能有其他对 s3 的借用(包括不可变借用)
*r2 = String::from("new world");
println!("{}", r2);
// 当 r1 和 r2 超出作用域后,它们不再引用 s3,避免了悬空指针问题
}
在这个例子中,通过所有权的移动避免了内存泄漏,因为Rust确保只有一个变量在任何时刻拥有资源的所有权,并且在所有者超出作用域时释放资源。通过借用规则避免了悬空指针问题,编译器会确保引用始终指向有效的对象,在同一时间只有符合规则的借用才被允许。