【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分于上海。

相关推荐
skywalk81632 小时前
段言的设计文档:中文编程赛道的竞争格局,谁在牌桌上?
开发语言·学习·编程
yi念zhi间2 小时前
C#实现控制台多区域输出
开发语言·c#
阿坤带你走近大数据2 小时前
分别介绍下java主流的开发框架、设计模式与对应编程语言的高级特性
java·开发语言·设计模式
小小龙学IT2 小时前
Go 后端开发中的并发模式:从 Goroutine 到 Pipeline 实战
开发语言·后端·golang
小短腿的代码世界2 小时前
Qt文本布局引擎深度解析:从QTextDocument排版到渲染的完整架构
开发语言·qt·架构
小小龙学IT3 小时前
Rust Web 框架 Axum:轻量级异步的下一代后端利器
前端·驱动开发·rust
Leweslyh3 小时前
《3GPP TS 28.312 面向移动网络的意图驱动管理服务》完整自学教程
开发语言·网络·php
2501_930707783 小时前
使用 C# 在 Excel 中合并并居中单元格
开发语言·c#·excel
好评笔记3 小时前
深度学习面试八股—— GRU(Gated Recurrent Unit)
人工智能·rnn·深度学习·算法·机器学习·gru·校招