Rust

2025年07月21日更新 7 人订阅
原价: ¥ 6 限时优惠
专栏简介 Rust编程语言之错误处理 Rust 语言之 flod Rust编程语言之Cargo、Crates.io详解 Rust编程语言之枚举与模式匹配 Rust语言 - 接口设计的建议之受约束(Constrained) Rust编程语言之无畏并发 Rust语言 - 接口设计的建议之灵活(flexible) Rust语言 - 接口设计的建议之显而易见(Obvious) Rust语言 - 接口设计的建议之不意外(unsurprising) Rust 实战:构建实用的 CLI 工具 HTTPie Rust编程语言学习之高级特性 Rust内存管理揭秘:深度剖析指针与智能指针 解决Rust中数组和切片的编译时大小问题 《Rust编程之道》学习笔记一 Rust Async 异步编程 简易教程 使用 Async Rust 构建简单的 P2P 节点 Rust编程语言入门之模式匹配 Rust async 编程 Rust编程语言之编写自动化测试 Rust编程语言之函数式语言特性:迭代器和闭包 《Rust编程之道》学习笔记二 Rust Tips 比较数值 使用 Rust 开发一个微型游戏 Rust编程初探:深入理解Struct结构体 深入理解Rust中的内存管理:栈、堆与静态内存详解 深入理解 Rust 结构体:经典结构体、元组结构体和单元结构体的实现 深入掌握 Rust 结构体:从模板到实例化的完整指南 深入理解Rust中的结构体:逻辑与数据结合的实战示例 深入理解 Rust 枚举:从基础到实践 掌握Rust字符串的精髓:String与&str的最佳实践 全面解析 Rust 模块系统:实战案例与应用技巧 Rust 中的 HashMap 实战指南:理解与优化技巧 掌握Rust模式匹配:从基础语法到实际应用 Rust 中的面向对象编程:特性与实现指南 深入理解 Rust 的 Pin 和 Unpin:理论与实践解析 Rust Trait 与 Go Interface:从设计到实战的深度对比 从零开始:用 Rust 和 Axum 打造高效 Web 应用 Rust 错误处理详解:掌握 anyhow、thiserror 和 snafu Rust 如何优雅实现冒泡排序 链表倒数 K 节点怎么删?Python/Go/Rust 实战 用 Rust 玩转数据存储:JSON 文件持久化实战 Rust实战:打造高效字符串分割函数 如何高效学习一门技术:从知到行的飞轮效应 Rust 编程入门:Struct 让代码更优雅 Rust 编程:零基础入门高性能开发 用 Rust 写个猜数游戏,编程小白也能上手! Rust 入门教程:变量到数据类型,轻松掌握! 深入浅出 Rust:函数、控制流与所有权核心特性解析 从零开始:用 Rust 和 Axum 打造高效 Web 服务 Rust 集合类型解析:Vector、String、HashMap 深入浅出Rust:泛型、Trait与生命周期的硬核指南 Rust实战:博物馆门票限流系统设计与实现 用 Rust 打造高性能图片处理服务器:从零开始实现类似 Thumbor 的功能 Rust 编程入门实战:从零开始抓取网页并转换为 Markdown 深入浅出 Rust:高效处理二进制数据的 Bytes 与 BytesMut 实战 Rust智能指针:解锁内存管理的进阶之道 用 Rust 打造命令行利器:从零到一实现 mini-grep 解锁Rust代码组织:轻松掌握Package、Crate与Module Rust 所有权:从内存管理到生产力释放 深入解析 Rust 的面向对象编程:特性、实现与设计模式 Rust + Protobuf:从零打造高效键值存储项目 bacon 点燃 Rust:比 cargo-watch 更爽的开发体验 用 Rust 打造微型游戏:从零开始的 Flappy Dragon 开发之旅 函数式编程的Rust之旅:闭包与迭代器的深入解析与实践 探索Rust编程之道:从设计哲学到内存安全的学习笔记 精读《Rust编程之道》:吃透语言精要,彻底搞懂所有权与借用 Rust 避坑指南:搞定数值比较,别再让 0.1 + 0.2 != 0.3 困扰你! 告别 Vec!掌握 Rust bytes 库,解锁零拷贝的真正威力 告别竞态条件:基于 Axum 和 Serde 的 Rust 并发状态管理最佳实践 Rust 异步编程实践:从 Tokio 基础到阻塞任务处理模式 Rust 网络编程实战:用 Tokio 手写一个迷你 TCP 反向代理 (minginx) 保姆级教程:Zsh + Oh My Zsh 终极配置,让你的 Ubuntu 终端效率倍增 不止于后端:Rust 在 Web 开发中的崛起之路 (2024数据解读) Rust核心利器:枚举(Enum)与模式匹配(Match),告别空指针,写出优雅健壮的代码 Rust 错误处理终极指南:从 panic! 到 Result 的优雅之道 想用 Rust 开发游戏?这份超详细的入门教程请收好! 用 Rust 实现 HTTPie:一个现代 CLI 工具的构建过程 Rust 异步实战:从0到1,用 Tokio 打造一个高性能并发聊天室 深入 Rust 核心:彻底搞懂指针、引用与智能指针 Rust 生产级后端实战:用 Axum + sqlx 打造高性能短链接服务 深入 Rust 内存模型:栈、堆、所有权与底层原理 Rust 核心概念解析:引用、借用与内部可变性

精读《Rust编程之道》:吃透语言精要,彻底搞懂所有权与借用

精读《Rust编程之道》:吃透语言精要,彻底搞懂所有权与借用“好读书,不求甚解;每有会意,便欣然忘食。”学习Rust就像开启一场独特的编程探险。它强大、安全,但也以其陡峭的学习曲线而闻名,尤其是其独特的“所有权”和“借用”机制,常常让初学者感到困惑。这篇文章是我在精读《Rust编程之道》第

精读《Rust编程之道》:吃透语言精要,彻底搞懂所有权与借用

“好读书,不求甚解;每有会意,便欣然忘食。”

学习 Rust 就像开启一场独特的编程探险。它强大、安全,但也以其陡峭的学习曲线而闻名,尤其是其独特的“所有权”和“借用”机制,常常让初学者感到困惑。

这篇文章是我在精读《Rust编程之道》第二章“语言精要”时,整理的一份核心学习笔记。它并非对书中内容的简单复刻,而是力求将那些关键且抽象的概念——从语言的基本构成,到语句与表达式的哲学,再到所有权系统的精髓——梳理得清晰明了。

  • 如果你正站在 Rust 的大门外犹豫不决;
  • 如果你对 let 和 let mut 背后的机理感到好奇;
  • 如果你希望一次性弄清“移动 (Move)”和“借用 (Borrow)”的区别;

那么,希望这份“欣然忘食”的笔记,能成为你学习路上的得力助手,助你稳固地迈出掌握 Rust 的第一步。

本文是经典书籍《Rust编程之道》第二章“语言精要”的深度学习笔记。文章系统性地梳理了 Rust 语言的五大核心组成部分(语言规范、编译器 rustc、核心库、标准库、包管理器 Cargo)。在此基础上,深入辨析了 Rust 中“一切皆表达式”的设计哲学,阐明了语句与表达式的本质区别。核心部分,笔记详细剖析了变量绑定、可变性 (mut)、位置表达式(左值)与值表达式(右值)等概念,并最终聚焦于 Rust 最具革命性的特性——所有权 (Ownership)、移动 (Move) 语义和借用 (Borrow) 机制。这篇笔记旨在为 Rust 学习者打下坚实的基础,清晰地解释那些初学时最容易混淆的关键概念。

第 2 章 语言精要

好读书,不求甚解;每有会意,便欣然忘食。

1 Rust 语言的基本构成

Rust 语言主要由以下几个核心部件组成:

  • 语言规范
  • 编译器
  • 核心库
  • 标准库
  • 包管理器

语言规范

Rust 语言规范主要由 Rust 语言参考(The Rust Reference)和 RFC 文档共同构成。

The Rust Reference:<https://doc.rust-lang.org/stable/reference/>

Rust 参考手册 中文版:<https://rustwiki.org/zh-CN/reference/>

Rust 规范文档:https://rustwiki.org/wiki/

Rust 官方文档中文教程:https://rustwiki.org/

编译器

Rust 是一门静态编译型语言。Rust官方的编译器叫 rustc,负责将 Rust 源代码编译为可执行文件或其他库文件(.a、.so、.lib、.dll 等)。

Rustc 有如下特点:

  • rustc 是跨平台的应用程序,支持UNIX/Linux 等类 UNIX 平台,也支持 Windows 平台。
  • rustc 支持交叉编译,可以在当前平台下编译出可运行于其他平台上的应用程序和库。
  • rustc 使用 LLVM 作为编译器后端,具有很好的代码生成和优化技术,支持多个目标平台。
  • rustc 是用 Rust 语言开发的,包含在 Rust 语言源码中。
  • rustc 对 Rust 源码进行词法语法分析、静态类型检查,最终将代码翻译为 LLVM IR。
  • rustc 输出的错误信息非常友好和详尽,是开发者的良师益友。

核心库

Rust 语言的语法由核心库和标准库共同提供。

Rust 核心库是标准库的基础。

可以通过在模块顶部引入 #![no_std] 来使用核心库。

核心库包含如下部分:

  • 基础的Trait
  • 基本原始类型
  • 一些内建宏

标准库

标准库包含的内容大概如下:

  • 一些基本 trait、原始数据类型、功能型数据类型和常用宏等
  • 并发、I/O 和运行时
  • 平台抽象
  • 底层操作接口
  • 可选和错误处理类型 Option 和 Result,以及各种迭代器等

包管理器

把按一定规则组织的多个 rs 文件编译后就得到一个包(crate)。

包是 Rust 代码的基本编译单元,也是程序员直接共享代码的基本单元。

Rust 社区的公开第三方包都集中在 crates.io 网站上面,它们的文档被自动发布到 docs.rs 网站上。

Rust 提供了非常方便的 包管理器 Cargo。

https://doc.rust-lang.org/cargo/

https://rustwiki.org/zh-CN/cargo/index.html

cargo new bin_crate
cargo new --lib lib_crate
  • cargo new 命令默认可以创建一个用于编写可执行二进制文件的项目。

  • cargo new 命令添加 --lib 参数,可以创建用于编写库的项目。

  • cargo build 对项目进行编译

  • cargo run 项目运行

2 语句与表达式

Rust 中的语法可以分成两大类:语句(Statement)和表达式(Expression)。

语句是指要执行的一些操作和产生副作用的表达式。

表达式主要用于计算求值。

语句分为两种:声明语句(Declaration statement)和表达式语句(Expression statement)。

  • 声明语句,用于声明各种语言项(Item),包括声明变量、静态变量、常量、结构体、函数等,以及通过 extern 和 use 关键字引入包和模块等。
  • 表达式语句,特指以分号结尾的表达式。此类表达式求值结果将会被舍弃,并总是返回单元类型 ()。
// extern crate std;
// use std::prelude::v1::*;
fn main() {
  pub fn answer() -> () {
    let a = 40;
    let b = 2;
    assert_eq!(sum(a, b), 42);
  }
  pub fn sum(a: i32, b: i32) -> i32 {
    a + b
  }
  answer();
}

Rust 会为每个 crate 都自动引入标准库模块,除非使用 #![no_std]#[no_std] 属性明确指定了不需要标准库。

关键字 fn 是 function 的缩写。

单元类型拥有唯一的值,就是它本身。

单元类型的概念来自 OCaml,它表示”没有什么特殊的价值“。

函数无返回值的函数默认不需要在函数签名中指定返回类型。

assert_eq! 是宏语句,是Rust提供的断言,允许判断给定的两个表达式求值结果是否相同。

Rust 编译器在解析代码的时候,如果碰到分号,就会继续往后面执行;

如果碰到语句,则执行语句;

如果碰到表达式,则会对表达式求值,如果分号后面什么都没有,就会补上单元值()。

当遇到函数的时候,会将函数体的花括号识别为块表达式(Block Expression)。

块表达式是由一对花括号和一系列表达式组成的,它总是返回块中最后一个表达式的值。

在某种程度上,可以将Rust看作是一切皆表达式。

3 变量与绑定

let 关键字创建变量

let 创建的变量一般称为 绑定(Binding)

它表明了标识符(Identifier)和值(Value)之间建立的一种关联关系。

位置表达式和值表达式

Rust 中的表达式一般可以分为位置表达式(Place Expression)和值表达式(Value Expression)。

在其他语言中,一般叫做左值(LValue)和右值(RValue)

位置表达式是表示内存位置的表达式。分别有以下几类:

  • 本地变量
  • 静态变量
  • 解引用(*expr)
  • 数组索引(expr[expr])
  • 字段引用(expr.field)
  • 位置表达式组合

通过位置表达式可以对某个数据单元的内存进行读写。

除此之外的表达式就是值表达式。

值表达式一般只引用了某个存储单元地址中的数据,它相当于数据值,只能进行读操作。

从语义角度来说,位置表达式代表了持久性数据,值表达式代表了临时数据。

表达式的求值过程在不同的上下文中会有不同的结果。

求值上下文也分为位置上下文(Place Context)和值上下文(Value Context)

位置上下文的表达式:

  • 赋值或者复合赋值语句左侧的操作数
  • 一元引用表达式的独立操作数
  • 包含隐式借用(引用)的操作数
  • math 判别式或let 绑定右侧在使用 ref 模式匹配的时候也是位置上下文。

除了上述几种情况,其余表达式都属于值上下文。

值表达式不能出现在位置上下文中。

pub fn temp() -> i32 {
  return 1;
}
fn main() {
  let x = &temp();
  temp() = *x;  // error
}

temp 函数调用时一个无效的位置表达式,它是值表达式。

不可变绑定与可变绑定

使用 let 关键字声明的位置表达式默认不可变,为不可变绑定。

fn main() {
  let a = 1;
  // a = 2; // immutable and error
  let mut b = 2;
  b = 3; // mutable
}

通过 mut 关键字,可以声明可变的位置表达式,即可变绑定。

可变绑定可以正常修改和赋值。

从语义上来说

let 默认声明的不可变绑定只能对相应的存储单元进行读取

let mut 声明的可变绑定可以对相应的存储单元进行写入

所有权与借用

当位置表达式出现在值上下文中时,该位置表达式将会把内存地址转移给另外一个位置表达式,这其实是所有权的转移。

fn main() {
  let place1 = "hello";
  let place2 = "hello".to_string();
  let other = place1;
  println!("{:?}", place1);
  let other = place2;
  println!("{:?}", place2); // Err: other value used here after move
}

因为 place1 是一个位置表达式,现在出现在了赋值操作符右侧,即一个值上下文内,所以 place1 会将内存地址转移给 other。

在语义上,每个变量绑定实际上都拥有该存储单元的所有权,这种转移内存地址的行为就是所有权(OwnerShip)的转移,在Rust中称为移动(Move)语义,那种不转移的情况实际上是一种复制(Copy)语义。

Rust 没有GC,所以完全依靠所有权来进行内存管理。

Rust 提供借用(Borrow)操作符(&),可以直接获取表达式的存储单元地址,即内存位置。

可以通过该内存位置对存储进行读取。

fn main() {
  let a = [1,2,3];
  let b = &a;
  println!("{:p}", b); // 0x7ffcbc067704
  let mut c = vec![1,2,3];
  let d = &mut c;
  d.push(4);
  println!("{:?}", d); // [1,2,3,4]
  let e = &42;
  assert_eq!(42, *e);
}

通过 println! 宏指定 {:p} 格式,可以打印 b 的指针地址,也就是内存地址。

注意,要获取可变引用,必须先声明可变绑定。

对于字面量 42 来说,其本身属于值表达式。

通过借用操作符,相当于值表达式在位置上下文中进行求值,所以编译器会为 &42 创建一个临时值。

值表达式在位置上下文中求值时会被创建临时值

将“ & ”称为借用操作符,通过借用操作符得到的类型叫引用(Reference)类型。

4 函数与闭包

main 函数代表程序的入口。

函数是通过关键字 fn 定义的。

定义一个 FizzBuzz 函数:输入一个数字,当数字是3的倍数时,输出fizz;当数字是5的倍数时,输出buzz;

当数字是3和5共同的倍数时,输出 fizzbuzz;其他情况返回该数字。

总结

通过对《Rust编程之道》第二章“语言精要”的学习,我们系统地回顾了 Rust 的核心基石。从宏观的生态构成(编译器、Cargo),到微观的语法哲学(语句与表达式),我们一步步深入,最终触及了 Rust 的灵魂——所有权系统。

本次学习的核心收获可以概括为以下三点:

  1. Rust 是一个完整的生态系统:它不仅仅是一门语言,rustc 编译器友好的提示、Cargo 强大的包管理能力,共同构成了高效、现代的开发体验。

  2. Rust 是“表达式驱动”的语言:理解块表达式、函数体返回值等“一切皆表达式”的理念,是写出地道、简洁 Rust 代码的关键。

  3. 所有权是内存管理的基石:Rust 摒弃了垃圾回收(GC),通过所有权(Ownership)、借用(Borrow) 和 生命周期(后续章节内容)这套静态分析机制,在编译期就保证了内存安全。理解 let 绑定的 Move 语义和 & 引用的 Borrow 语义,是跨越 Rust 学习最大障碍的核心所在。

正如开篇所言,“每有会意,便欣然忘食”。今天,我们对 Rust 的这些基础规则有了更深的“会意”。这不仅是理论知识的填充,更是编程思维模式的一次重要升级。掌握了这些“语言精要”,我们才算真正拿到了进入 Rust 世界的门票。接下来,让我们带着这些基础,继续探索 Rust 更加广阔和强大的功能吧!

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论