【Rust】03-所有权、移动与复制

所有权、移动与复制

学习目标

  • 理解所有权规则。
  • 区分移动语义和复制语义。
  • 知道 String 与整数等基础类型在赋值时的差异。

所有权规则

Rust 的所有权系统有三条核心规则:

  1. Rust 中每个值都有一个所有者。
  2. 同一时间一个值只能有一个所有者。
  3. 当所有者离开作用域,值会被释放。

示例:

rust 复制代码
fn main() {
    {
        let name = String::from("Rust");
        println!("{name}");
    } // name 离开作用域,String 占用的堆内存被释放
}

这套规则让 Rust 不需要垃圾回收器,也能自动管理内存。

栈与堆

简单类型如整数、布尔值通常存放在栈上:

rust 复制代码
let x = 5;
let y = x;
println!("{x}, {y}");

这段代码可以运行,因为 i32 实现了 Copy。赋值时复制了一份值。

String 这类拥有堆内存的数据不同:

rust 复制代码
fn main() {
    let s1 = String::from("hello");
    let s2 = s1;

    // println!("{s1}"); // 编译错误:s1 已经被移动
    println!("{s2}");
}

s1 被移动到 s2 后,s1 不再有效。这样可以避免两个变量在离开作用域时重复释放同一块堆内存。

移动

移动不是深拷贝。对 String 来说,移动通常只是复制指针、长度和容量等元信息,然后让原变量失效。

rust 复制代码
fn main() {
    let message = String::from("hello");
    take(message);
    // println!("{message}"); // 编译错误
}

fn take(value: String) {
    println!("{value}");
}

message 传给函数,也会发生移动。函数参数 value 成为新的所有者。

克隆

如果确实需要复制堆数据,可以使用 clone

rust 复制代码
fn main() {
    let s1 = String::from("hello");
    let s2 = s1.clone();

    println!("{s1}, {s2}");
}

clone 可能分配新内存并复制内容,所以成本比移动更高。看到 clone 时,应该意识到这里发生了显式复制。

Copy Trait

实现了 Copy 的类型在赋值或传参时会复制,不会移动。常见 Copy 类型包括:

  • 整数、浮点数、布尔值、字符。
  • 只包含 Copy 类型的元组。
  • 不可变引用 &T

StringVec<T> 等拥有堆资源的类型通常不实现 Copy

rust 复制代码
fn main() {
    let x = 10;
    print_number(x);
    println!("{x}"); // 仍然可用
}

fn print_number(n: i32) {
    println!("{n}");
}

返回所有权

函数可以把所有权返回给调用者:

rust 复制代码
fn main() {
    let s1 = String::from("hello");
    let s2 = add_world(s1);

    println!("{s2}");
}

fn add_world(mut value: String) -> String {
    value.push_str(", world");
    value
}

但如果每次只是想读取值,来回移动所有权会很麻烦。下一篇会介绍借用和引用,它们是 Rust 日常开发中更常用的方式。

常见误区

  • 移动不是深拷贝,而是所有权转移。
  • 编译器不允许使用已经被移动的变量。
  • 不要为了绕过所有权错误到处写 clone;先判断是否可以借用。
  • Copy 是隐式复制,Clone 是显式复制。

练习

  1. 写一个函数接收 String 并打印它,观察调用后原变量是否还能使用。
  2. 把上面的例子改成使用 clone,观察两个变量都可用。
  3. i32 重复同样实验,理解 Copy 的行为。

后记

2026年6月10日17点07分于上海。

相关推荐
BothSavage10 小时前
Trae远程开发中DeepSeek自定义模型4054错误的排查与修复
算法
小林ixn10 小时前
从暴力到KMP:一道题彻底搞懂字符串匹配的前世今生
算法
烬羽12 小时前
字符串算法入门:从反转字符串到回文判断,面试不再慌
算法·面试
独孤留白12 小时前
从C到Rust:Rust 的 Trait 不是Interface,那是什么?
rust
花褪残红青杏小20 小时前
Rust图像处理第7节-马赛克像素化:分块取平均色实现打码风格
rust·webassembly·图形学
先吃饱再说1 天前
判断回文字符串,从一行代码到双指针优化
算法
黄敬峰1 天前
深入理解算法核心:从递归思想、数组扁平化到快速排序
算法
得物技术1 天前
从狂野代码到按目标生产:得物推荐 AI Harness 的工程化实践|AICon 演讲整理
人工智能·算法·架构