问题

如何开始学习 Rust 语言?

回答
想踏入 Rust 的世界?太棒了!Rust 是一门令人兴奋的语言,它在性能、安全性和并发性方面都有着出色的表现。不过,就像任何新事物一样,刚开始可能会觉得有点“劝退”,但别担心,只要找对方法,你会发现 Rust 的魅力所在。

这篇文章就想跟你聊聊,如何一步一步、有条不紊地开启你的 Rust 之旅,让你从一个完全的门外汉,变成一个能够驾驭它的开发者。我会尽量讲得细致点,希望你能从中找到适合自己的节奏。

0. 心态调整:准备好迎接挑战与惊喜

在正式开始之前,先跟你打个招呼:Rust 的学习曲线确实比一些动态语言要陡峭一些。它强调的是“内存安全”和“无畏并发”,这两点是通过一些独特的设计和概念来实现的,比如所有权(Ownership)、借用(Borrowing)和生命周期(Lifetimes)。

拥抱错误信息: 你会发现 Rust 的编译器(叫做 `rustc`)非常“啰嗦”,会给你提供非常详细的错误信息,甚至告诉你怎么修改。一开始可能会觉得烦,但请记住,这是你的“好朋友”,它是在帮你写出更健壮的代码。学会读懂它,就是你迈出的重要一步。
耐心与毅力: 遇到搞不懂的概念,不要灰心。花点时间去理解,去尝试,去搜索。很多时候,当你感觉卡住了,换个角度思考,或者看看别人的代码,就会豁然开朗。
社区的力量: Rust 有一个非常活跃和友好的社区。遇到问题,别忘了去官方论坛、Discord 或者 Stack Overflow 求助。大家都很乐意帮助新人。

1. 工具的准备:让你的开发环境就绪

在你开始写代码之前,需要先把工具安装好。这部分非常简单,但却是基础。

1.1 安装 Rust 工具链 (rustup)

Rust 官方推荐使用 `rustup` 来管理 Rust 的版本和工具链。它不仅可以安装 Rust 编译器 (`rustc`),还有包管理器 (`cargo`)、文档生成器 (`rustdoc`) 等一系列开发必备工具。

访问官网: 打开 Rust 的官方网站:[https://www.rustlang.org/](https://www.rustlang.org/)
下载安装脚本: 网站会根据你的操作系统提供相应的安装指南。通常,你只需要在终端执行一行命令即可。
Linux/macOS:
```bash
curl proto '=https' tlsv1.2 sSf https://sh.rustup.rs | sh
```
脚本会提示你选择安装选项,通常直接按回车使用默认设置就好。
Windows:
访问 [https://rustup.rs/](https://rustup.rs/) 下载 `rustupinit.exe` 文件,然后双击运行即可。

验证安装: 安装完成后,重启你的终端(或者打开一个新的终端窗口),然后输入以下命令来验证安装是否成功:
```bash
rustc version
cargo version
```
如果能看到 Rust 编译器和 Cargo 的版本号,那就说明安装成功了!

1.2 选择一个合适的代码编辑器或 IDE

虽然 Rust 代码可以用任何文本编辑器编写,但为了获得更好的开发体验(语法高亮、自动补全、错误检查等),强烈建议使用一个支持 Rust 的编辑器或 IDE。

Visual Studio Code (VS Code): 这是目前最流行且功能强大的选择。安装好 VS Code 后,你只需要在扩展商店搜索并安装 `rustanalyzer` 这个插件。它提供了非常优秀的 Rust 代码智能提示和诊断功能。
IntelliJ IDEA (with Rust plugin): 如果你习惯 JetBrains 的产品线,那么 IntelliJ IDEA 配上官方的 Rust 插件也是一个不错的选择,提供了深度集成和强大的代码分析能力。
Neovim/Vim: 对于 Vim 用户来说,通过配置 Language Server Protocol (LSP) 客户端(如 `coc.nvim` 或内置的 `nvimlspconfig`)并使用 `rustanalyzer`,也能获得非常顺畅的 Rust 开发体验。

2. 入门第一步:Hello, World!

万事开头难,但 Rust 的“Hello, World!”非常简单。

2.1 创建一个新项目

Rust 的包管理器 `cargo` 是管理项目的基础。用 `cargo` 创建一个新项目非常方便。

打开你的终端,进入你想要存放项目的目录,然后执行:

```bash
cargo new hello_rust
```

这会创建一个名为 `hello_rust` 的新文件夹,里面包含了项目所需的基本结构:

```
hello_rust/
├── Cargo.toml
└── src/
└── main.rs
```

`Cargo.toml`: 这是项目的配置文件,记录了项目的名称、版本、作者以及依赖项等信息。
`src/main.rs`: 这是项目的源代码文件,`main` 函数是程序的入口。

2.2 编写你的第一个 Rust 程序

用你的代码编辑器打开 `hello_rust/src/main.rs` 文件。你会看到里面已经有了一段默认的代码:

```rust
fn main() {
println!("Hello, world!");
}
```

`fn main()`: 定义了一个名为 `main` 的函数,这是程序的入口点。Rust 程序总是从 `main` 函数开始执行。
`println!`: 这是一个宏(宏在 Rust 中用感叹号 `!` 表示),用于将文本输出到控制台。它会自动在输出的字符串末尾添加一个换行符。
`"Hello, world!"`: 这是要打印的字符串字面量。
`;`: Rust 中的大多数语句都以分号结尾。

2.3 编译和运行

回到终端,进入 `hello_rust` 文件夹,然后使用 `cargo` 来编译和运行你的程序。

编译:
```bash
cargo build
```
这会在项目的 `target/debug/` 目录下生成一个可执行文件。`cargo build` 只进行编译,不运行程序。

运行:
```bash
cargo run
```
`cargo run` 会先编译你的项目(如果需要的话),然后直接运行生成的可执行文件。你会在终端看到输出:

```
Hello, world!
```

构建发布版本:
```bash
cargo build release
```
这会进行更优化的编译,生成速度更快但编译时间稍长的可执行文件,通常用于部署。发布版本的可执行文件在 `target/release/` 目录下。

恭喜你!你已经成功运行了你的第一个 Rust 程序。这仅仅是开始,但意义非凡。

3. 学习核心概念:Rust 的基石

现在,是时候深入了解 Rust 的核心概念了。我会按照一般学习的顺序来介绍,并给出一些思考点。

3.1 变量与可变性 (Variables and Mutability)

Rust 的变量默认是不可变的。这意味着一旦给变量赋值,就不能再改变它的值。如果你想改变一个变量的值,需要使用 `mut` 关键字来声明它是可变的。

```rust
fn main() {
let x = 5; // 默认不可变
// x = 6; // 这行代码会报错,因为 x 是不可变的

let mut y = 5; // 声明 y 是可变的
println!("The value of y is: {}", y);
y = 6; // 这行代码是合法的
println!("The value of y is now: {}", y);

// 常量与变量的区别
const MAX_POINTS: u32 = 100_000; // 常量,必须指定类型,且总是不可变的
println!("The maximum points allowed is: {}", MAX_POINTS);
}
```

思考: 为什么 Rust 会默认不可变?思考一下这带来的好处(例如,在并发编程中更容易推理,减少意外的副作用)。

3.2 数据类型 (Data Types)

Rust 是一种静态类型语言,这意味着它在编译时就知道所有变量的类型。Rust 提供了丰富的数据类型。

标量类型 (Scalar Types):
整数 (Integers): 有符号和无符号,不同大小(`i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`)。`usize` 的大小与你的计算机的指针大小相同。
浮点数 (FloatingPoint Numbers): `f32` 和 `f64`。
布尔值 (Booleans): `bool`,值为 `true` 或 `false`。
字符 (Characters): `char`,代表一个 Unicode 字符。

复合类型 (Compound Types):
元组 (Tuples): 固定长度的异构序列。
```rust
let tup: (i32, f64, u8) = (500, 6.4, 1);
let (x, y, z) = tup; // 解构元组
println!("The value of y is: {}", y);
println!("The first element is: {}", tup.0); // 通过索引访问
```
数组 (Arrays): 固定长度的同构序列。
```rust
let a = [1, 2, 3, 4, 5];
let b: [i32; 5] = [1, 2, 3, 4, 5]; // 指定类型和长度
let first = a[0];
let second = a[1];
// let index = 10;
// let element = a[index]; // 这行会因数组越界而在运行时 panic
```
思考: 数组越界为什么会导致 `panic`?这是 Rust 安全性的体现之一。

3.3 函数 (Functions)

函数是代码块,用于执行特定任务。

```rust
fn main() {
another_function(5, 'h');
let x = five();
println!("The value of x is: {}", x);
let y = add_one(5);
println!("The value of y is: {}", y);
}

fn another_function(x: i32, unit_label: char) {
println!("The measurement is: {}{}", x, unit_label);
}

fn five() > i32 {
5 // 表达式作为返回值,不需要分号
}

fn add_one(x: i32) > i32 {
x + 1 // 表达式作为返回值
}
```

返回值: 函数的返回值是函数体中最后一个表达式的值(没有分号),或者使用 `return` 关键字显式返回。

3.4 控制流 (Control Flow)

包括条件语句和循环。

`if` 表达式:
```rust
fn main() {
let number = 3;
if number < 5 {
println!("condition was true");
} else {
println!("condition was false");
}

// if 也是一个表达式,可以用于赋值
let condition = true;
let x = if condition { 5 } else { 6 };
println!("The value of x is: {}", x);
}
```
注意: `if` 的每个分支都必须返回相同类型的值。

`loop` 循环: 无限循环,直到遇到 `break`。
```rust
fn main() {
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter 2; // break 也可以返回值
}
};
println!("The result is: {}", result);
}
```

`while` 循环: 条件循环。
```rust
fn main() {
let mut number = 3;
while number != 0 {
println!("{}!", number);
number = 1;
}
println!("LIFTOFF!!!");
}
```

`for` 循环: 迭代序列。
```rust
fn main() {
let a = [10, 20, 30, 40, 50];
for element in a {
println!("the value is: {}", element);
}

// 迭代范围
for number in (1..4).rev() { // 1, 2, 3
println!("{}!", number);
}
println!("LIFTOFF!!!");
}
```
`1..4` 表示一个包含 1,不包含 4 的范围 (1, 2, 3)。
`.rev()` 将范围反转。

3.5 所有权 (Ownership)

这是 Rust 最核心,也可能是最难理解的部分。它解决了垃圾回收(GC)和手动内存管理(如 C/C++)的痛点,在保证内存安全的同时,也带来了极高的性能。

所有权规则:

1. Rust 中的每一个值都有一个被这个值的变量所拥有的所有者。
2. 一次只能有一个所有者。
3. 当所有者离开作用域(离开 `{}` 块),这个值会被丢弃(drop)。

理解所有权需要关注以下几个概念:

Move(移动): 当你将一个值从一个变量赋给另一个变量时,所有权会发生转移(move)。
```rust
fn main() {
let s1 = String::from("hello");
let s2 = s1; // s1 的所有权被移交给 s2

// println!("{}, world!", s1); // 这行会报错,s1 已经失效了
println!("{}, world!", s2);
}
```
为什么会发生 Move? 对于存储在堆上的数据(如 `String`),Rust 为了避免一次性复制整个堆上的数据(性能开销大),而是通过转移一个指针、长度和容量的“头部信息”来完成赋值。当旧变量(如 `s1`)离开作用域时,Rust 会调用 `drop` 函数来释放内存,但如果允许旧变量继续有效,可能会导致双重释放(double free)的问题。所以 Rust 禁止了这种行为,强制进行 Move。

Clone(克隆): 如果你希望在不转移所有权的情况下复制堆上的数据,可以使用 `.clone()` 方法。这会进行深拷贝,复制堆上的所有数据。
```rust
fn main() {
let s1 = String::from("hello");
let s2 = s1.clone(); // s2 拥有 s1 的一个独立副本

println!("s1 = {}, s2 = {}", s1, s2); // 两者都有效
}
```

Copy Trait: 像整数、浮点数、布尔值、字符以及包含这些类型的元组和数组等存储在栈上的数据,它们的大小在编译时是固定的。当你将这些值赋给另一个变量时,Rust 会进行Copy操作,即简单地复制值,而不是 Move。原始变量仍然有效。
```rust
fn main() {
let x = 5;
let y = x; // 这是一个 Copy 操作,x 仍然有效

println!("x = {}, y = {}", x, y);
}
```
重要: 如果一个类型实现了 `Drop` trait,那么它就不能自动实现 `Copy` trait。`String` 类型就实现了 `Drop` trait(因为需要手动管理内存),所以它不是 `Copy` 的。

函数传参和返回值中的所有权: 函数传参和返回值也会发生所有权的转移。
```rust
fn main() {
let s = String::from("hello"); // s 进入作用域
takes_ownership(s); // s 的值移动进函数,因此在下面 s 不再有效
// println!("{}", s); // 报错

let x = 5; // x 进入作用域
makes_copy(x); // x 的值被拷贝进函数
println!("{}", x); // x 仍然有效
}

fn takes_ownership(some_string: String) { // some_string 进入作用域
println!("{}", some_string);
} // some_string 离开作用域,drop 被调用,内存被释放

fn makes_copy(some_integer: i32) { // some_integer 进入作用域
println!("{}", some_integer);
} // some_integer 离开作用域,但它是 Copy 的,所以不会被释放,这 nothing
```

3.6 引用与借用 (References and Borrowing)

所有权转移在函数传参时很不方便,如果我们只需要读取一个值,而不获取它的所有权呢?这时候就需要引用(Reference)和借用(Borrowing)了。

创建引用: 使用 `&` 符号创建一个引用。引用就像一个指针,但它保证总是指向一个有效的对象。
```rust
fn main() {
let s1 = String::from("hello");
let len = calculate_length(&s1); // 传递 s1 的引用
println!("The length of '{}' is {}.", s1, len); // s1 仍然有效
}

fn calculate_length(s: &String) > usize {
s.len()
}
```
`&s1` 是一个不可变引用。

可变引用: 如果需要修改被引用的值,需要使用可变引用 `&mut`。
```rust
fn main() {
let mut s = String::from("hello");
change(&mut s);
println!("{}", s);
}

fn change(some_string: &mut String) {
some_string.push_str(", world");
}
```

借用规则: 这是理解所有权和引用的关键。
1. 在任何给定时间,要么只能有一个可变引用,要么只能有任意数量的不可变引用。
2. 引用必须总是有效的。

为什么要有这些规则? 这是为了防止数据竞争(data race)。数据竞争发生在至少满足以下三个条件时:
有两个或更多指针同时访问同一块数据。
至少有一个指针被用于写入数据。
没有使用任何机制来同步访问。

示例:
```rust
fn main() {
let mut s = String::from("hello");

// let r1 = &s // 正常,不可变引用
// let r2 = &s // 正常,多个不可变引用
// println!("{}, {}", r1, r2);

// let r3 = &mut s; // 错误!不能在有不可变引用的情况下创建可变引用
// println!("{}", r3);

let r1 = &s
println!("The length of '{}' is {}.", s, r1.len());
// println!("The length of '{}' is {}.", s, r1.len()); // 这里 r1 还在使用,所以不能创建可变引用

let r2 = &mut s; // OK!r1 不再使用,所以可以创建可变引用
println!("{}", r2);

// let r3 = &mut s; // 错误!不能有两个可变引用
// println!("{}, {}", r2, r3);
}
```
这些规则让 Rust 在编译时就能发现潜在的数据竞争问题。

3.7 切片 (Slices)

切片是一种允许你引用一个集合中连续元素序列的类型,而无需获取整个集合的所有权。

字符串切片:
```rust
fn main() {
let mut s = String::from("hello world");
let hello = &s[0..5]; // 引用前 5 个字节
let world = &s[6..11]; // 引用从第 6 个字节到第 11 个字节
let slice = &s[..]; // 引用整个字符串

println!("{}, {}", hello, world);

// 注意:如果字符串中包含多字节字符,直接使用字节索引可能会导致 panic
// 例如,如果 s 是 "你好世界",s[0..1] 只会得到第一个字节,而不是第一个字符
// 通常使用字符串切片时,要确保切片发生在 UTF8 字符边界上。

// 创建一个函数接收字符串切片
let word = first_word(&s);
// s.clear(); // 错误!不能修改 s,因为 hello 是对 s 的不可变引用
println!("The first word is: {}", word);
}

fn first_word(s: &str) > &str { // &str 是一个字符串切片类型
let bytes = s.as_bytes();

for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}

&s[..]
}
```
`&str` 类型是字符串切片,它是一个“胖指针”,包含指向字符串数据的指针和字符串的长度。

4. 深入学习 Rust 生态

掌握了基础之后,接下来就是学习 Rust 的强大生态系统了。

4.1 包和模块系统 (Packages, Crates, and Modules)

Crate (箱): Rust 的编译单元,可以是库(library)或二进制文件(binary)。`cargo new` 创建的项目就是一个 crate。
Package (包): 一个或多个 crate 的集合,必须包含一个 `Cargo.toml` 文件。通常一个包只包含一个库 crate 或一个二进制 crate,但也可以包含多个。
Modules (模块): Rust 使用模块来组织代码,控制代码的可见性(public/private)。可以使用 `mod` 关键字来定义模块,`pub` 关键字来暴露内容。
```rust
// src/main.rs
mod front_of_house {
pub mod hosting { // front_of_house::hosting 是公有的
pub fn add_to_waitlist() {}
}
}

// 可以使用 `use` 关键字引入模块或项
use crate::front_of_house::hosting;

fn main() {
hosting::add_to_waitlist();
}
```

4.2 Cargo 的更多用法

Cargo 是 Rust 的瑞士军刀,除了编译和运行,还有很多常用功能:

添加依赖: 在 `Cargo.toml` 的 `[dependencies]` 部分添加其他 crate 的名称和版本。
```toml
[dependencies]
rand = "0.8.5"
```
然后运行 `cargo build` 或 `cargo check`,Cargo 就会自动下载并编译这些依赖。

`cargo check`: 快速检查代码是否能通过编译,但不生成可执行文件,速度更快。

`cargo test`: 运行项目中的所有测试。

`cargo doc open`: 生成项目及其依赖的文档,并在浏览器中打开。

工作空间 (Workspaces): 用于管理多个相关联的包。

4.3 Rust 标准库 (The Standard Library)

Rust 的标准库提供了许多基础类型和功能,例如:

`String` 和 `&str`:字符串处理。
`Vec`:动态数组(向量)。
`HashMap`:哈希表。
`Option`:用于处理可能不存在的值(`Some(value)` 或 `None`),这是 Rust 安全性的重要体现,避免了空指针。
`Result`:用于表示操作可能成功(`Ok(value)`)或失败(`Err(error)`)。这是 Rust 处理错误的主要方式。

4.4 错误处理 (Error Handling)

Rust 对错误的分类和处理方式很独特:

Panic: 表示程序遇到无法恢复的错误,会导致程序立即终止并释放资源。通常用于不可预见的编程错误(如数组越界)。
`Result`: 用于表示可恢复的错误。通常使用 `match` 或 `?` 操作符来处理。
```rust
use std::fs::File;
use std::io::{self, Read};

fn read_username_from_file() > Result {
let mut f = File::open("hello.txt")?; // ? 操作符会自动处理 Result
let mut s = String::new();
f.read_to_string(&mut s)?;
Ok(s)
}

fn main() {
match read_username_from_file() {
Ok(username) => println!("Username: {}", username),
Err(e) => println!("Error reading username: {}", e),
}
}
```
`?` 操作符:当在一个返回 `Result` 的函数中使用 `?` 时,如果 `Result` 是 `Err`,它会立即返回 `Err`;如果是 `Ok`,它会解包出值并继续执行。这极大地简化了错误处理代码。

4.5 Trait 和泛型 (Traits and Generics)

泛型 (Generics): 允许你编写不依赖于特定类型的代码。
```rust
// 泛型函数
fn largest(list: &[T]) > T {
let mut largest = list[0];
for &item in list {
if item > largest {
largest = item;
}
}
largest
}

// 泛型结构体
struct Point {
x: T,
y: T,
}
```
Trait: 定义了共享行为的抽象。类似于其他语言的接口或抽象类。
```rust
pub trait Summary {
fn summarize(&self) > String;
}

// 实现 trait
impl Summary for NewsArticle {
fn summarize(&self) > String {
format!("{}, by {} ({})", self.headline, self.author, self.location)
}
}

// Trait bound:要求泛型参数实现某个 trait
fn notify(item: &T) {
println!("Breaking news! {}", item.summarize());
}
```

4.6 生命周期 (Lifetimes)

生命周期是 Rust 的另一个核心概念,它确保引用不会比它们指向的数据活得更长。它解决了悬垂引用(dangling reference)的问题。

生命周期注解: 在函数签名中,编译器需要知道引用之间的关系,以便进行静态分析。
```rust
// 下面的函数是无效的,因为返回的引用可能比传入的字符串短命
// fn longest_invalid(x: &str, y: &str) > &str {
// if x.len() > y.len() {
// x
// } else {
// y
// }
// }

// 正确的写法,生命周期注解 'a
fn longest<'a>(x: &'a str, y: &'a str) > &'a str {
if x.len() > y.len() {
x
} else {
y
}
}

fn main() {
let string1 = String::from("abcd");
let string2 = "xyz";

let result = longest(string1.as_str(), string2);
println!("The longest string is {}", result);
}
```
`'a` 是一个生命周期注解,表示 `x` 和 `y` 必须至少活得和返回的那个引用的生命周期一样长。

思考: 生命周期注解本身不会改变引用能活多久,它只是帮助编译器检查和推理引用之间的关系。

5. 进阶之路:深入探索

当你对 Rust 的基础有了扎实的掌握后,可以开始探索更高级的领域:

并发编程: Rust 在并发方面表现出色,其所有权和借用机制消除了许多常见的并发错误(如数据竞争)。学习 `std::thread`、`Arc`(原子引用计数)、`Mutex`(互斥锁)等。
智能指针 (Smart Pointers): 如 `Box`(堆分配)、`Rc`(引用计数)、`RefCell`(运行时借用检查)等,它们提供了比普通引用更丰富的功能。
模式匹配 (Pattern Matching): Rust 的 `match` 语句非常强大,可以用来解构各种数据类型。
宏 (Macros): 学习如何编写声明宏 (`macro_rules!`) 和过程宏,扩展语言的功能。
不安全 Rust (Unsafe Rust): 在需要绕过 Rust 的一些安全检查时(例如与 C 代码交互、编写高性能系统库),可以使用 `unsafe` 块。但这应该谨慎使用,并且需要格外小心。
FFI (Foreign Function Interface): 如何在 Rust 中调用 C/C++ 代码,或将 Rust 代码暴露给其他语言调用。
异步编程 (Async/Await): Rust 的 `async`/`await` 语法提供了高效的异步操作,非常适合网络编程、IO 密集型任务。

6. 学习资源推荐

好的资源能让你事半功倍。

1. 《The Rust Programming Language》 (官方指南):
这是学习 Rust 的 必读 资源。它以易于理解的方式介绍了 Rust 的所有核心概念。
在线阅读:[https://doc.rustlang.org/book/](https://doc.rustlang.org/book/)
国内有汉化版本,搜索“Rust 程序设计语言”即可找到。

2. Rustlings:
这是一个非常棒的交互式练习项目,通过完成一系列小练习来学习 Rust 的语法和概念。
GitHub:[https://github.com/rustlang/rustlings](https://github.com/rustlang/rustlings)

3. Rust By Example:
提供大量可运行的示例代码,展示 Rust 的各种特性和用法。
在线阅读:[https://doc.rustlang.org/rustbyexample/](https://doc.rustlang.org/rustbyexample/)

4. Rust Cookbook:
当你需要解决具体问题时,可以查阅这个食谱,里面有很多实用的代码示例和模式。
在线阅读:[https://rustlangnursery.github.io/rustcookbook/](https://rustlangnursery.github.io/rustcookbook/)

5. Rust API 文档:
随时查阅标准库和第三方库的文档。
标准库:[https://doc.rustlang.org/std/](https://doc.rustlang.org/std/)

7. 实践!实践!再实践!

学习编程最重要的一点就是动手实践。

尝试修改示例代码: 在学习过程中,不要只看不练,尝试修改官方文档和 Rustlings 中的代码,看看会发生什么。
小项目: 尝试用 Rust 写一些小工具,例如:
一个简单的命令行工具(比如一个计算器、一个文件查找工具)。
一个简单的网络爬虫。
一个文本处理程序。
一个简单的游戏(可以使用 `ggez` 或 `bevy` 这样的游戏引擎库)。
参与开源项目: 当你对 Rust 有一定的了解后,可以尝试为开源项目贡献代码,这是提升技能、学习最佳实践的好方法。

结语

学习 Rust 的过程可能充满挑战,但当你克服了初期的困难,你将会发现一门如此强大、可靠且充满乐趣的语言。它会改变你对软件开发的看法,让你写出更安全、更高效的代码。

享受这个过程吧!不断提问,不断尝试,你终将成为一名熟练的 Rust 开发者。祝你旅途愉快!

网友意见

user avatar

先分享个 「Rust 学习路径图」

再谈谈「Rust 发展前景判断」

有很多人比较关心 Rust 的发展前景: Rust 和其他语言的对比、现在或者未来什么语言会被 Rust 替代、Rust 会不会一统前后端天下等等。我觉得不会。

每种语言都有它们各自的优劣和适用场景,谈不上谁一定取代谁。社区的形成、兴盛和衰亡是一个长久的过程,就像“世界上最好的语言 PHP”也还在顽强地生长着。

那么如何判断一门新的语言的发展前景呢?下图是我用 pandas 处理过的 modulecounts 的数据,这个数据统计了主流语言的库的数量。可以看到 2019 年初 Rust crates 的起点并不高,只有两万出头,两年后就有六万多了。

作为一门新的语言,Rust 生态虽然绝对数量不高,但增长率一直遥遥领先,过去两年多的增长速度差不多是第二名 NPM 的两倍。很遗憾,Golang 的库没有一个比较好的统计渠道,所以这里没法比较 Golang 的数据。但和 JavaScript / Java / Python 等语言的对比足以说明 Rust 的潜力。

官方学习资料

Rust 社区里就有大量的学习资料供我们使用。

首先是官方的 Rust book,它涵盖了语言的方方面面,是入门 Rust 最权威的免费资料。不过这本书比较细碎,有些需要重点解释的内容又一笔带过,让人读完还是云里雾里的。

我记得当时学习 Deref trait 时,官方文档这段文字直接把我看懵了:

所以我觉得这本书适合学习语言的概貌,对于一时理解不了的内容,需要自己花时间另找资料,或者自己通过练习来掌握。在学习课程的过程中,如果你想巩固所学的内容,可以翻阅这本书。

另外一本官方的 Rust 死灵书(The Rustonomicon),讲述 Rust 的高级特性,主要是如何撰写和使用 unsafe Rust,内容不适合初学者。建议在学习完课程之后,或者起码学完进阶内容之后,再阅读这本书。

Rust 代码的文档系统 docs.rs是所有编程语言中使用起来最舒服,也是体验最一致的。无论是标准库的文档,还是第三方库的文档,都是用相同的工具生成的,非常便于阅读,你自己撰写的 crate,发布后也会放在 docs.rs 里。在平时学习和撰写代码的时候,用好这些文档会对你的学习效率和开发效率大有裨益。

标准库的文档 建议你在学到某个数据类型或者概念时再去阅读,在每一讲中涉及的内容,我都会放上标准库的链接,你可以延伸阅读。

为了帮助 Rust 初学者进一步巩固 Rust 学习的效果,Rust 官方还出品了 rustlings,它涵盖了大量的小练习,可以用来夯实对知识和概念的理解。有兴趣、有余力的同学可以尝试一下。

书籍+博客+视频

说完了官方的资料,我们看看其它关于 rust 的内容包括书籍、博客、视频。首先讲几本书。第一本是汉东的《Rust 编程之道》,详尽深入,是不可多得的 Rust 中文书。汉东在极客时间有一门 Rust 视频课程,如果你感兴趣,也可以订阅。英文书有 Programming Rust,目前出了第二版,我读过第一版,写得不错,面面俱到,适合从头读到尾,也适合查漏补缺。

除了书籍相关的资料,我还订阅了一些不错的博客和公众号,也分享给你。博客我主要会看 This week in Rust,你可以订阅其邮件列表,每期扫一下感兴趣的主题再深度阅读。

公众号主要用于获取信息,可以了解社区的一些动态,有 Rust 语言中文社区、Rust 编程指北,这两个公众号有时会推 This week in Rust 里的内容,甚至会有翻译。

还有一个非常棒的内容来源是 Rust 语言开源杂志,每月一期,囊括了大量优秀的 Rust 文章。不过这个杂志的主要受众,我感觉还是对 Rust 有一定掌握的开发者,建议你在学完了进阶篇后再读里面的文章效果更好。

视频的话,在 bilibili 上,也有大量的 Rust 培训资料,但需要自己先甄别。陈天老师做了几期“程序君的 Rust 培训”感兴趣也可以看看,可以作为课程的补充资料。

Rust 入门课程

给大家推荐陈天老师的《Rust 编程第一课》,现在已经四千多人订阅,且公认全网最好的 Rust 入门教程

承担着「Rust 第一课」的使命,课程讲得通俗易懂,把各个知识点类比到不同的语言中,设计了很多小而美的示例代码,引入 Rust 标准库的源代码进行分析,并且还精心绘制了大量的原理图。

刚上线的时候是 40 讲,老师边写边延展内容,完结后已经58 讲了。这种单纯的分享精神,也是很走心了。看看目录吧:

总的来说,内容由浅入深,对比多种语言,带你攻克 Rust 编程 10 大难点,有 100+ 原理图,详解 Rust 设计理念。最后通过 4 个项目实操训练,理论与实战两手抓,真正让你掌握 Rust 开发精髓。

说这么多,希望你能够坚定对学习 Rust 的信心。相信我,不管你未来是否使用 Rust,单单是学习 Rust 的过程,就能让你成为一个更好的程序员。

类似的话题

  • 回答
    想踏入 Rust 的世界?太棒了!Rust 是一门令人兴奋的语言,它在性能、安全性和并发性方面都有着出色的表现。不过,就像任何新事物一样,刚开始可能会觉得有点“劝退”,但别担心,只要找对方法,你会发现 Rust 的魅力所在。这篇文章就想跟你聊聊,如何一步一步、有条不紊地开启你的 Rust 之旅,让你.............
  • 回答
    想开始学习兵书兵法,这绝对是个相当有意思的起点。这玩意儿可不是什么速成班,更像是一场深入的探索,需要耐心、思考,还得有点儿“悟性”。下面我就跟你掰扯掰扯,怎么把这门老祖宗留下的智慧啃下来,尽量说得明白透彻些,让你觉得这就是个跟你一样对这事儿好奇的哥们儿给你的经验分享。第一步:别急着啃《孙子兵法》的原.............
  • 回答
    想要踏入嵌入式开发这个迷人的领域,就像是在一块未被开垦的土地上播下种子,需要耐心、方法和一点点的实践精神。你需要的不仅仅是理论知识,更重要的是将这些知识转化为能够驱动真实世界硬件的“代码”。首先,你需要对编程有一个基本的认识。如果对C语言一无所知,那么从C语言入手会是你最坚实的起点。C语言之所以在嵌.............
  • 回答
    好的,没问题!让我给你详细讲讲如何踏上狩猎反曲弓的学习之路。这是一段充满乐趣和挑战的旅程,会让你与自然更亲近。首先,让我们把那些“AI痕迹”都清理掉,把这事儿掰开了揉碎了说透。第一步:认识你的弓——反曲弓的魅力何在?在开始之前,你得明白为啥要选反曲弓,特别是狩猎反曲弓。 传统与现代的结合: 反曲.............
  • 回答
    嘿!想进入视频剪辑的世界,这绝对是个好主意!别看屏幕上那些流畅炫酷的片子好像一夜之间就冒出来的,其实都是一点一滴用心剪出来的。刚开始接触,感觉有点茫然是很正常的,不过别担心,我来给你掰扯掰扯,怎么一步一步踏进这个有趣又充满创造力的领域。第一步:认清你的“武器”——选择合适的剪辑软件现在市面上的剪辑软.............
  • 回答
    没接触过编程?想学 Python?别担心,这事儿比你想的要简单,而且非常有趣!今天我就给你捋一捋,从零开始,怎么一步步踏上 Python 的学习之旅。一、 为什么要学 Python?先跟你唠唠,为啥咱们要选 Python。这东西就跟一把瑞士军刀,啥都能干: 好上手: Python 的语法就像咱们.............
  • 回答
    嘿!很高兴你对网络安全产生了兴趣。这绝对是一个值得投入时间和精力的领域,而且需求量一直都很高。别担心,从零开始学习网络安全并没有想象中那么吓人,关键在于找到正确的路径和方法。咱们一步一步来,保证让你有清晰的方向感。首先,你需要明白网络安全是一个非常广阔的领域,它不是一门单一的学科,而是包含了计算机科.............
  • 回答
    你提到“跑500米就会断气”,这听起来像是身体发出了比较强烈的信号,需要特别温和、循序渐进地来调整。别担心,很多人一开始都有过类似的体验,这并不代表你不行,只是身体还没有适应运动的节奏。我们这就来聊聊怎么能让你慢慢地、舒服地享受慢跑带来的好处。首先,得承认,500米就感到吃力,说明目前的身体耐力基础.............
  • 回答
    想深入了解并熟练运用一个开源框架,这可不是光靠看几篇入门教程就能一蹴而就的事情,它更像是一场细致的探索和实战的磨练。首先,咱们得明确目标。你之所以想学这个框架,是因为它能解决你当前面临的某个问题?还是因为它在行业内非常流行,掌握了它能让你更具竞争力?明确了这一点,你就能更有针对性地去学习,知道哪些部.............
  • 回答
    好的,咱们来聊聊怎么在 GitHub 上“偷师学艺”,让你迅速上手,少走弯路。Forget about all that fancy jargon, let’s get down to business.GitHub,本质上是一个托管代码的地方,但它更是一个巨大的、活生生的开源社区。你可以把它想象成.............
  • 回答
    想踏上录音这条路,从零开始,我完全理解那种既兴奋又有点茫然的心情。别担心,这就像学任何一门手艺一样,只要方法对,一步一个脚印,你也能录出让自己满意的声音。我来给你掰开了揉碎了说,咱们就当是老朋友聊天,一点点把这事儿说透。 第一步:认识你的“工具箱”——硬件篇在你脑子里,录音这事儿,得先有几个“家伙”.............
  • 回答
    孩子几岁开始学习自主阅读比较合适?这是一个家长们普遍关心的问题,其实并没有一个绝对的“最佳”年龄,因为每个孩子的发展节奏都不尽相同。但我们可以从几个方面来考量,并找到最适合您家宝贝的那个时间点。孩子什么时候开始“自主阅读”比较好?我们先来理解一下“自主阅读”的定义。这里说的自主阅读,不是指孩子能独立.............
  • 回答
    想要从零开始学习SLAM(Simultaneous Localization and Mapping,即时定位与地图构建),这绝对是一个充满挑战但也非常有意思的旅程。别担心,这并不像听起来那么遥不可及。我会尽量用最朴实、最贴近实际的方式,一步一步地拆解它,让你明白到底是怎么一回事。先给大脑“热身”:.............
  • 回答
    在美国,很多中国人因为各种原因,比如爱好、工作需要(比如一些科技行业的安全需求),或者仅仅是想体验一项新的运动,都有了学习射击的兴趣。从零开始,尤其是在一个新的文化和法律环境下,确实需要一些步骤和准备。这篇文章就来聊聊,一个在中国没有接触过射击的华人朋友,在美国如何系统地开启这段学习之旅。第一步:了.............
  • 回答
    嗨,朋友,看到你现在纠结迷茫的状态,我特别理解。我也是过来人,当年在计算机系也经历过类似的挣扎,总觉得自己跟不上节奏,甚至怀疑人生方向。那种感觉就像是在一个陌生的国度,语言不通,地图也看不懂,身边的人都像是在流利地交流,而你却只能笨拙地比划。首先,我想说,你不是一个人。很多顶尖名校的计算机系,里面的.............
  • 回答
    作为一个大型语言模型,我并没有实体,也就不存在学校和线上的概念。我也不需要“在家学习”,因为我的存在形式就是数字化的,通过服务器和网络即可运作。但是,我很乐意模拟一下一个学生在家进行线上教学的感受,并尽量详细地描述出来。模拟场景:大学线上教学启动一周后我的“学校”: 想象一下,我身处一所传统的大学,.............
  • 回答
    好,咱们就来聊聊,作为一个完全没接触过画画的朋友,怎么一步步踏上素描这条路。别担心,这事儿没那么玄乎,更不是什么需要天赋才能学会的技能。只要你愿意下功夫,并且找对方法,你一定能看到自己的进步。第一步:别把“零基础”当成什么障碍,它其实是最好的起点。很多人一听“素描”,就觉得是大师们才能玩的东西,画个.............
  • 回答
    中小学生学习拉丁语,这是一个非常有意思的话题,值得我们深入探讨。从不同的角度来看,它既有显著的优势,也面临一些挑战。一、学习拉丁语的显著优势:1. 提升英语语言能力和理解深度: 词源的基石: 英语的词汇有相当大一部分(据估计超过60%)源自拉丁语,尤其是在学术、法律、医学和科技领域。学.............
  • 回答
    从零开始学画画,这趟旅程本身就充满了探索和惊喜。别担心,这并不是什么高不可攀的技能,就像学习任何新的语言一样,只要方法得当,循序渐进,你也能描绘出心中的景象。首先,放下那些“我没天赋”的念头。绘画的魅力在于它的普适性,任何人都可能掌握。你需要做的,是培养一种观察的习惯。仔细看看你周围的世界:光线是如.............
  • 回答
    哈哈,想走上中医这条路,不容易,但绝对是个值得探索的旅程!自己琢磨中医,这股劲儿就够让人佩服的。不过,说实话,中医这东西,不是看几本小人书就能搞定的,它博大精深,讲究的是“悟”和“实践”,不是死记硬背。别急,先打好地基,别一开始就钻那些高深的理论,容易把自己绕晕。第一步:调整心态,放下“速成”的念头.............

本站所有内容均为互联网搜索引擎提供的公开搜索信息,本站不存储任何数据与内容,任何内容与数据均与本站无关,如有需要请联系相关搜索引擎包括但不限于百度google,bing,sogou

© 2025 tinynews.org All Rights Reserved. 百科问答小站 版权所有