Rust所有权和借用规则示例
众所周知,所有权是Rust区别于其他语言的一大特色,只要代码满足了所有权规则,我们就不用担心内存的泄露的问题。
让代码在编译阶段就解决内存的问题,而不是在运行崩溃后再调试。
Rust中,所有权和借用的规则其实并不复杂,所有权有3条规则,借用只有2条规则。
所有权的规则
1. Rust中的每一个值都有一个对应的变量作为它的所有者
这个规则很好理解,比如下面的2个值 5
和 hello
分别属于变量 x
和 y
fn main() {
let x = 5;
let y = String::from("hello");
println!("x = {}, and y = {}", x, y);
}
2. 在同一时间内,值有且仅有一个所有者
比如下面的示例,当 x
的值给了 y
之后,x
就不能再用了,值hello
只能有一个所有者。
fn main() {
let x = String::from("hello");
let y = x;
println!("x = {}, y = {}", x, y); // 这里会报错
}
3. 当所有者离开自己的作用域时,它持有的值就会被释放掉
fn main() {
let x = String::from("hello");
{
let y = String::from("world");
println!("{} {}", x, y);
}
println!("{} {}", x, y); // 这里会报错,获取不到 y,y已经释放了。
}
借用(引用)的规则
Rust中,引用和借用是一个意思,用借用能更准确的表达变量传递的含义。
1. 在任何一段给定的时间里,你要么只能拥有一个可变引用,要么只能拥有任意数量的不可变引用
y
和z
都拥有x
的不可变借用。
fn main() {
let x = 5;
let y = &x;
let z = &x;
println!("y = {}, z = {}", y, z);
}
如果 y
拥有可变借用,而 z
拥有不可变借用,是不行的。
fn main() {
let mut x = 5;
let y = &mut x;
let z = &x; // 这里会报错,因为同一段时间内,既有x的不可变借用,又有可变借用
println!("y = {}, z = {}", y, z);
}
2. 借用总是有效的
只要借用能编译,就说明借用是有效的,编译器会帮助我们确保借用都是有效的。
fn main() {
let x = vec![1, 2, 3];
lost(x);
let y = &x; // 这里编译会报错,因为 x 已经转移到 lost 函数中,在 main 中失效了
println!("y = {:?}", y);
}
fn lost(x: Vec<i32>) {
println!("lost: {:?}", x);
}
下面这样借用就不会报错,因为x
只是借用给 no_lost
函数。
fn main() {
let x = vec![1, 2, 3];
not_lost(&x);
let y = &x;
println!("y = {:?}", y);
}
fn not_lost(x: &Vec<i32>) {
println!("lost: {:?}", x);
}
总结
所有权和借用是Rust确保内存安全使用的重要手段,上面的示例用最简单的方式展示了这些规则。
实际项目中,刚开始其实很难保证所有权和借用的规则,会经常遇到编译不了的情况。
但是,一旦养成了习惯,写代码时,脑中自然浮现变量在内存中的情况,自然就写出了内存安全的代码。