Jason Pan

Rust学习笔记

潘忠显 / 2025-02-14


最近在学习 Rust,主要在看 doc。在这个页面做些笔记。

我不会搬运文档中直白的东西,主要分享一些相较其他语言比较新鲜的东西

持续更新,感兴趣的同学可以关注。

0. 安装和帮助文档

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

上边这一条命令的安装 Rust 相关的所有东西,包括:

最后这个 rustup 中,还提供获取 Rust 本地文档的功能——其实只是调用了浏览器打开了 index 页面。本地内容跟 https://doc.rust-lang.org/stable/book/ 是一样的。

rustup doc --book

rust_doc

其他语言也有类似的文档,比如 Go 的 godoc 工具跟代码是一致的,Python 的 pydoc (实际调用可能是 pydoc3.13 这样) 只能显示你已经安装的模块的文档,跟官网文档不一样。

1. Option 和 Some

之前有接触过 Java、Scala,其中也有 SomeOption 之类,但当时没有怎么理解。

这里恰好 Rust 文档里也有详细的描述,顺便仔细看了一下。

Option 是什么

在 Rust 中,Option是一个非常核心的枚举类型,它用于表示一个值可能存在或不存在的情况。Option的定义如下:

enum Option<T> {
    Some(T),
    None,
}

从上面的定义可以看到,Option 是一个带有泛型枚举。其中,Some 是一个包含具体值的变体,而 None 则表示没有值。

let x: Option<i32> = Some(10);

上边的语句,表示有一个类型为 Option<i32> 的变量,它的值是 Some(5),表示这个 Option 包含了整数 5。也可以赋值是 None,表示没有值。

为什么需要 Option

Option 其实可以被视为对低级语言(如 C 语言)中指针的一种高级抽象和优化,可以减少空指针异常带来潜在问题,提供一种更安全的方式来处理可能不存在的值

你可以显式地表示一个值可能存在(Some(T))或不存在(None编译器会强制你处理所有可能的情况,从而避免了空指针错误。

所谓的「编译器强制处理」,一方面要使用其中的值,必须先判断 Option 是个 Some;另一方面在使用 match 一个 Option 变量的时候,需要处理 Some 和 None —— 这个是 match 的特性。

下边代码,在编译的阶段就会报错,因为 None 没有被覆盖到

fn main() {
    let t = Some(5);
    match t {
        Some(value) => println!("Got a value: {}", value),
        // None => println!("No value found"),
    }
}

Some(var) 的方式绑定到某个变量上,结合 let if 语句,也可以带来更好的可读性。

fn main() {
    let t = Some(5);
    if let Some(user) = t {
        println!("Found user: {:?}", user);
    } else {
        println!("No value found")
    }
}

在上面的代码中,if let 表达式使得你只需要关心 Some 的情况,而对于 None 则可以忽略,从而写出简洁、优雅的代码。

区别于 Scala 中的 Option 实现

虽然 Rust 中的 Option 与 Scala 中的 Optional 在设计目的和使用方式上非常相似,但在具体实现由明显差异。

前边介绍了在 Rust 中,Option 是一个枚举类型。

而在 Scala 中,Option 是一个抽象类,有两个子类:SomeNone。三个类定义如下:

sealed abstract class Option[+A] extends Product with Serializable
case class Some[+A](value: A) extends Option[A]
case object None extends Option[Nothing]

两者都有个 Option 实现了很多的方法:

rust_scala_option