首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Rust专项——Rust 所有权基础:安全内存管理的核心

Rust专项——Rust 所有权基础:安全内存管理的核心

作者头像
红目香薰
发布2025-12-16 16:21:48
发布2025-12-16 16:21:48
1930
举报
文章被收录于专栏:CSDNToQQCodeCSDNToQQCode

本章系统讲解 Rust 的所有权(Ownership)模型,它是 Rust 在无 GC 的前提下实现内存安全与高性能的关键机制。你将理解“值的唯一所有者”、移动(move)、复制(copy)、释放(drop),以及与之相关的借用(borrow)与切片(slice)等基础概念,并能看懂和修复典型报错。

1. 三大所有权规则

  • 每个值在任意时刻有且只有一个所有者(owner)。
  • 当所有者离开作用域(scope)时,值会被自动丢弃(drop)。
  • 发生所有权转移(move)后,旧变量将不再有效。
代码语言:javascript
复制
fn main() {
    let s = String::from("hello"); // s 拥有 String 的所有权
    takes_ownership(s);             // 所有权移动到函数参数
    // println!("{}", s);          // E0382: s 已被移动,不能再使用

    let x = 42;
    makes_copy(x);                   // i32 实现 Copy,不发生 move
    println!("x 仍然可用: {}", x);   // OK
}

fn takes_ownership(s: String) {
    println!("got {}", s);
} // s 离开作用域,自动 drop

fn makes_copy(n: i32) {
    println!("n = {}", n);
} // n 离开作用域,但为栈上 Copy 类型,无需 drop
在这里插入图片描述
在这里插入图片描述

2. Move 与 Copy:何时会“被移动”?

  • Move:默认针对在堆上分配或包含资源的类型(如 String, Vec<T>, 自定义类型等)。
  • Copy:小且固定大小的标量类型(如整数、浮点、bool, char,以及仅由 Copy 成员组成的 #[derive(Copy, Clone)] 结构体)。
代码语言:javascript
复制
#[derive(Copy, Clone)]
struct Point { x: i32, y: i32 }

fn main() {
    let a = Point { x: 1, y: 2 }; // Copy
    let b = a;                    // 复制,不是 move
    println!("a=({}, {}), b=({}, {})", a.x, a.y, b.x, b.y);

    let s1 = String::from("hi");
    let s2 = s1;                  // move
    // println!("{}", s1);       // E0382: moved
    println!("{}", s2);
}
在这里插入图片描述
在这里插入图片描述

判断是否 Copy 的经验法:若类型需要自定义释放逻辑或拥有堆资源,通常不是 Copy。

3. 克隆(Clone)与深拷贝

如需保留原变量且获得一份独立数据,使用 clone()

代码语言:javascript
复制
fn main() {
    let s1 = String::from("hello");
    let s2 = s1.clone();          // 深拷贝
    println!("s1={}, s2={}", s1, s2);
}

clone 可能有性能开销,按需使用。

在这里插入图片描述
在这里插入图片描述

4. 借用(Borrow)与引用(Reference)入门

  • 共享借用:&T,可读不可写,可同时存在多个。
  • 可变借用:&mut T,可写,但同一作用域内同一数据“至多一个可变借用”且不可与任意共享借用并存。
代码语言:javascript
复制
fn main() {
    let mut s = String::from("abc");

    let r1 = &s;          // 共享借用
    let r2 = &s;          // 共享借用可以多个
    println!("{}, {}", r1, r2);

    // let r3 = &mut s;   // E0502: 不能在有共享借用的同时创建可变借用

    let r3 = &mut s;      // 当前作用域内没有活动的共享借用,OK
    r3.push_str("def");
    println!("{}", r3);
}
在这里插入图片描述
在这里插入图片描述

常见错误:

  • E0502/E0499:同一数据同时存在多个可变借用,或可变与共享借用冲突。
  • 修复思路:缩小借用的活跃范围(使用更小的作用域或尽快消费引用)。

5. 悬垂引用与生命周期(预告)

Rust 禁止产生悬垂引用:

代码语言:javascript
复制
fn dangle() -> &String {           // 编译错误:返回引用但被引用的值将被释放
    let s = String::from("hi");   // s 在函数结束时被 drop
    &s                             // 返回悬垂引用 -> 被拒绝
}

生命周期(lifetime)用于在编译期证明引用始终有效。详细内容见 5.3。

6. 返回值与所有权

函数返回值会将所有权转移给调用者:

代码语言:javascript
复制
fn main() {
    let s = give_ownership();      // 所有权从函数返回给 s
    let t = take_and_return(s);    // s 移动到函数,再由返回值给 t
    println!("{}", t);
}

fn give_ownership() -> String {
    String::from("data")
}

fn take_and_return(x: String) -> String {
    println!("got {}", x);
    x
}

7. 切片(Slice)与借用

切片是对集合中一段连续元素的“只读借用”,本身不拥有数据:

代码语言:javascript
复制
fn first_word(s: &str) -> &str {          // 接受 &str(字符串切片)
    let bytes = s.as_bytes();
    for (i, &b) in bytes.iter().enumerate() {
        if b == b' ' { return &s[..i]; }
    }
    &s[..]
}

fn main() {
    let s = String::from("hello world");
    let w = first_word(&s);               // 将 String 借为 &str
    println!("{}", w);
}

切片常见于:&str, &[T], &mut [T]

8. 常见报错与速修

  • E0382(moved value):发生 move 后继续使用旧变量。
    • 修复:改用 clone() 或重新获取所有权(函数返回)。
  • E0502/E0499(借用冲突):同一数据的可变借用与共享借用同时存在。
    • 修复:缩小借用作用域;分块代码;必要时重构数据流。
  • E0597(借用过短):引用的生命周期不足以满足使用场景。
    • 修复:延长被借用值的生命周期,或调整返回/借用策略。

9. 小练习

  1. 解释为什么下面代码无法编译,并改成可编译版本:
代码语言:javascript
复制
let mut s = String::from("hi");
let a = &s;
let b = &mut s;     // 错误:共享与可变借用冲突
println!("{}", a);
  1. 补全函数 keep_longer<'a>(a: &'a str, b: &'a str) -> &'a str,返回更长的切片。

到这里你已掌握所有权的核心逻辑。下一节我们将系统学习“借用与引用”的规则与实战技巧,再下一节深入生命周期。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-10-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 三大所有权规则
  • 2. Move 与 Copy:何时会“被移动”?
  • 3. 克隆(Clone)与深拷贝
  • 4. 借用(Borrow)与引用(Reference)入门
  • 5. 悬垂引用与生命周期(预告)
  • 6. 返回值与所有权
  • 7. 切片(Slice)与借用
  • 8. 常见报错与速修
  • 9. 小练习
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档