众所周知,所有权是Rust区别于其他语言的一大特色,只要代码满足了所有权规则,我们就不用担心内存的泄露的问题。
让代码在编译阶段就解决内存的问题,而不是在运行崩溃后再调试。
Rust中,所有权和借用的规则其实并不复杂,所有权有3条规则,借用只有2条规则。
这个规则很好理解,比如下面的2个值 5
和 hello
分别属于变量 x
和 y
fn main() { let x = 5; let y = String::from("hello"); println!("x = {}, and y = {}", x, y); }
比如下面的示例,当 x
的值给了 y
之后,x
就不能再用了,值hello
只能有一个所有者。
fn main() { let x = String::from("hello"); let y = x; println!("x = {}, y = {}", x, y); // 这里会报错 }
fn main() { let x = String::from("hello"); { let y = String::from("world"); println!("{} {}", x, y); } println!("{} {}", x, y); // 这里会报错,获取不到 y,y已经释放了。 }
Rust中,引用和借用是一个意思,用借用能更准确的表达变量传递的含义。
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); }
只要借用能编译,就说明借用是有效的,编译器会帮助我们确保借用都是有效的。
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确保内存安全使用的重要手段,上面的示例用最简单的方式展示了这些规则。
实际项目中,刚开始其实很难保证所有权和借用的规则,会经常遇到编译不了的情况。
但是,一旦养成了习惯,写代码时,脑中自然浮现变量在内存中的情况,自然就写出了内存安全的代码。