前言
所有权机制是Rust的核心功能之一,对于初学者算是一个重难点,它保证了程序无需GC,即可自动化的释放内存
希望这篇博客可以帮助你快速理解所有权机制
概念
Rust的值都只有一个变量是该值的所有者
所有者可以切换,但是值在任一时刻有且仅有一个所有者
当所有者离开作用域,该值将被丢弃
错误示例
在变量的作用域之外访问该变量
fn main() {
{
let s = String::from("hello"); // 创建字符串,该字符串的所有者是变量s
} // 离开作用域,该字符串被丢弃
println!("{}", s); // 编译报错,此时变量s已被释放,无法访问变量s
}
访问一个所有权被转移的变量
fn main() {
let s = String::from("hello"); // 创建字符串,该字符串的所有者是变量s
let a = s; // 字符串的所有权从变量s传递给变量a
println!("{}",s); // 编译报错,此时字符串的所有权已被转移,无法在通过变量s访问字符串
}
访问一个所有权被转移的变量
fn main() {
let s = String::from("hello"); // 创建字符串,该字符串的所有者是变量s
takes_ownership(s); // 字符串的所有权从变量s传递给函数takes_ownership
println!("{}",s); // 编译报错,此时字符串的所有权已被转移,无法在通过变量s访问字符串
}
fn takes_ownership(s: String) {
println!("我拿到了字符串\"{}\"的所有权", s); // 拿到字符串的所有权
} // 离开作用域,该字符串被丢弃
借用
在上述错误示例中,我们不难发现,如果我们把String字符串的所有权传递给函数,那么等到函数结束,我们就无法在使用该字符串了,对于我们,这显然是无法接受的,那么几种解决方法解决这个问题,例如
fn main() {
let mut s = String::from("hello");
s = takes_ownership(s);
println!("{}", s);
}
fn takes_ownership(s: String) -> String {
println!("我拿到了字符串\"{}\"的所有权", s); // 拿到字符串的所有权
s // 返回该字符串
}
fn main() {
let mut s = String::from("hello");
s = takes_ownership(s);
println!("{}", s);
}
fn takes_ownership(s: String) -> String {
println!("我拿到了字符串\"{}\"的所有权", s); // 拿到字符串的所有权
s // 返回该字符串
}
但是上述做法并不优雅,Rust推荐的做法是我们通过借用来解决这个问题,借用就是创建一个引用的行为,例如
fn main() {
let s = String::from("hello");
takes_ownership(&s); // 将字符串的引用传递给函数
println!("{}", s);
}
fn takes_ownership(s: &String) { // 借用到字符串的引用
println!("我借用到了字符串\"{}\"的引用", s);
} // 此时字符串的所有权并没传递给函数,应此该函数没有资格释放该字符串
如果我们需要在函数内部修改字符串,那么我们可以借用字符串的可变引用
fn main() {
let mut s = String::from("hello");
takes_ownership(&mut s); // 将字符串的引用传递给函数
println!("{}", s);
}
fn takes_ownership(s: &mut String) { // 借用到字符串的可变引用
println!("我借用到了字符串\"{}\"的可变引用", s);
s.push_str(" world"); // 修改该字符串
} // 此时字符串的所有权并没传递给函数,应此该函数没有资格释放该字符串
可变引用虽好,但是有个注意事项,就是同一时刻可变引用只能有一个,当存在可变引用的时候,就不能有不可变引用,但是当可变引用不存在的时候,就可以存在数个不可变引用,例如文章来源:https://www.toymoban.com/news/detail-722584.html
fn main() {
let mut s = String::from("hello");
let (a, b) = (&s, &s); // 借用两个字符串的不可变引用
println!("不可变借用a:{}, 不可变借用b:{}", a, b);
let c = &mut s; // 借用字符串的可变引用,此时前面的两个不可变引用不再生效
c.push_str(" world");
println!("{}", c);
}
还有一个注意事项就是,引用的内容必须合法,例如下面的错误示范文章来源地址https://www.toymoban.com/news/detail-722584.html
fn main() {
let s = dangle();
}
fn dangle() -> &String {
let s = String::from("hello"); // 创建字符串,该字符串的所有者是变量s
&s // 返回字符串的引用,但是此时字符串要已经离开作用域被释放了,因此当函数结束,这个引用将是一个非法的悬垂引用,不过还好,在rust中这种行为无法通过编译
}
引用规则总结
- 在任意时刻只能有一个可变引用,要么只能有多个不可变引用
- 引用必须有效
到了这里,关于Rust所有权机制的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!