关于rust的所有权以及借用borrowing

发布于:2025-09-06 ⋅ 阅读:(15) ⋅ 点赞:(0)

如何从内存中申请空间来存放程序的运行内容,如何在不需要的时候释放这些空间,以下的几种方式:

  1. 垃圾回收机制(GC),在程序运行时不断寻找不再使用的内存,典型代表:Java、Go。
  2. 手动管理内存的分配和释放, 在程序中,通过函数调用的方式来申请和释放内存,典型代表:C++。
  3. 通过所有权来管理内存,编译器在编译时会根据一系列规则进行检查。

其中 Rust 选择了第三种,最妙的是,这种检查只发生在编译期,因此对于程序运行期,不会有任何性能上的损失。Ownership和Borrowing也是rust特有的机制,Rust 用所有权避免内存泄漏和悬垂指针,不用垃圾回收。

以下尝试用最简单的方式来解释这2种机制。

✅ 一、所有权(Ownership)——“一个东西只能有一个人管”
规则:每个值有且仅有一个“主人”(变量),主人离开作用域,值就被销毁。赋值或传参时,所有权被转移(不是复制!)。

let s1 = String::from("hello");
let s2 = s1;        // s1 把所有权给了 s2
println!("{}", s1); // ❌ 错误!s1 已经“失效”

总结:s1 被“move”了,不能再用。

✅ 二、借用(Borrowing)——“用一下,不拿走”
想用值但不拿走所有权?用引用(&)。

let s1 = String::from("hello");
let len = calc_length(&s1);  // 借用 s1
println!("{}", s1);               // ✅ OK!s1 还在

fn calc_length(s: &String) -> usize {
    s.len()  // 只是“读”,不拥有
}

总结: 🔑 &s1 是“借用”——你用,但不归你。

✅ 三、可变借用——“借走还能改”
默认借用是只读的。要修改,必须可变借用。

let mut s = String::from("hello");
change(&mut s);           // 可变借用,注意:当使用 mut 关键字声明一个变量时,该变量就可以被修改
println!("{}", s);        // 输出 "hello world"

fn change(s: &mut String) {
    s.push_str(" world");	//追加
}

⚠️ 注意:同一时间,只能有一个可变借用,或多个不可变借用(不能又读又写)。
这种限制的好处就是使 Rust 在编译期就避免数据竞争,数据竞争可由以下行为造成:

  1. 两个或更多的指针同时访问同一数据
  2. 至少有一个指针被用来写入数据
  3. 没有同步数据访问的机制
fn main() {
    let mut s = String::from("hello");

    let r1 = &s;      // ✅ 不可变借用
    let r2 = &s;      // ✅ 还可以再借一个(读-读允许)
    let r3 = &mut s;  // ❌ 错误!不能在 r1、r2 存在时借可变引用

    println!("{}, {}, and {}", r1, r2, r3);
}

let mut s = String::from("hello");
let r1 = &mut s;        // ✅ 可变借用
let r2 = &s;            // 不行!只要有 &mut s,就不能再有 &s。


//很多时候,大括号可以帮我们解决一些编译不通过的问题,通过手动限制变量的作用域:
let mut s = String::from("hello");
{
    let r1 = &mut s;
} // r1 在这里离开了作用域,所以我们完全可以创建一个新的引用
let r2 = &mut s;

✅ 总结
所有权:值只有一个主人,主人走了,值就没了。
引用:&x 借来用,不拿走。
可变引用:&mut x 借来还能改,但只能一个。


网站公告

今日签到

点亮在社区的每一天
去签到