# Rust语言速成

> 学习Rust最好的方式，就是拿它写个OS。 ——作者

Rust语言独具特色，然而学习曲线十分陡峭。在你享受到它为系统编程带来的好处之前，很可能直接被它编译器严格的检查机制所劝退。

为了帮助大家尽快地上手Rust，这里简要列出了我个人认为合理地学习顺序，供大家参考。这里我们假设读者已经具有一定C语言编程经验。

#### 存活阶段

* 工具链基础使用方法
* Rust基础语法：
  * 变量、函数、数据类型、控制流
  * 数组、字符串、结构体、元组、枚举
* unsafe：指针操作

至此，你应该能够用Rust写等价的C代码了！

#### 入门阶段

* Rust内存模型：从此告别SegmentFault
  * 可变性
  * 所有权，移动语义
  * 生命周期和借用
* Rust高级语法：现代语言特性
  * 模式匹配
  * 闭包/lambda表达式，函数式编程
* 面向对象：Better C with Class
  * 成员变量
  * 接口：Trait，Trait对象（动态分派）
  * 泛型（静态分派）
* 核心库：你要的轮子，都在这里
  * Option、Result、错误处理机制
  * 容器类：Vec、VecDeque、BTreeSet、BinaryHeap……
  * 迭代器、链式调用
  * 堆分配，智能指针：Box、Rc、Arc……
  * 消灭unsafe：运行时借用检查RefCell
  * 了解其它常用Trait
* 项目管理：工程化与模块化
  * 模块系统，文件层次
  * 包管理系统，项目配置文件Cargo.toml

至此，你应该开始体会到Rust为系统编程带来的便利了！

#### 高级阶段

* 宏
* 反射
* 安全并发机制
* 与C语言互操作
* 内联汇编

## Rust样例

这里给出一些需求的最简单实现。代码位于：[RustSamples](https://github.com/wangrunji0408/RustSamples)。

目前包括以下功能样例：

* Rust调用C
* C调用Rust

## 值得一提的特点

### 大量泛型

如果你阅读过一些Rust代码就会发现，**泛型**这一特性被广泛运用，频率高于其它任何一门常用语言。在C++中，泛型/模板是晦涩和强大的代名词，而在Rust中，它平凡而常见。

其实，Rust中的泛型大部分只是为了解决一个简单的需求——**调用接口**。

举个例子，我们要定义一个接口I，并在一个函数中使用它。在C++中，我们会使用**基类指针**：

```cpp
abstract class I {
    int func();
}

int call_func(I* p) {
    return p->func();
}
```

在Rust中其实也有类似的事物——[**Trait对象**](https://kaisery.github.io/trpl-zh-cn/ch17-02-trait-objects.html#trait-对象执行动态分发)：

```rust
trait I {
    fn func(&self) -> i32;
}

fn call_func(p: Box<I>) -> i32 {
    p.func()
}
```

但它并不常用。我们注意到p的类型是`Box<I>`，意味着传入对象必须是分配在堆上。如果把这里改成`I`，就会出现以下错误：

> the trait bound `I: std::marker::Sized` is not satisfied \[E0277] `I` does not have a constant size known at compile-time

Rust文档中也具体说明了[Trait对象的使用条件——对象安全](https://kaisery.github.io/trpl-zh-cn/ch17-02-trait-objects.html#trait-对象要求对象安全)。

由于以上方法用起来有诸多不便，因此我们常用**泛型**实现接口调用：

```rust
// T是一个实现了trait I的类型
fn call_func<T: I>(p: T) -> i32 {
    p.func()
}

// 当<>中的内容比较多时，
// 也可以把泛型约束放在外面
fn call_func<T>(p: T) -> i32 
    where T: I 
{ p.func() }
```

其实用泛型的方法实现接口调用在C++中也可以实现，但由于目前C++缺乏泛型约束（C++20的标准：Concept），导致传入错误类型后编译器会吐出一堆垃圾。很少有人使用。

使用泛型相比基类指针还有一个好处：性能更好。使用基类指针调用接口函数时，需要**在运行时查虚表**，而用泛型就能**在编译时确定最终类型**，节省一次查表开销，编译器还能做更多内联优化。前者称为**动态分派**，后者称为**静态分派**。但如果对象类型只能在运行时确定，那就必须用前者了。

### 没有继承

Rust作为一个面向对象语言，竟然没有继承？！

是的！很多新兴的编程语言都逐渐抛弃了继承这一特性，比如和它相爱相杀的Go。

回忆OOP里面诸多的设计原则，其中有一条就是：**使用组合代替继承**。其原因就是我们总会继承一些多余的东西，造成类间高度的耦合性。最早的C++最复杂，之后的Java做了一些简化（抽象出接口，只允许单继承），不过还不够彻底。到了Rust这代语言，继承被彻底抛弃，只保留了接口。

不过，Rust也提供了一个代替方案：[**Deref特性**](https://kaisery.github.io/trpl-zh-cn/ch15-02-deref.html)。使用方法是把“父类”当作“子类”的一个内部变量，Deref提供了一个语法糖来自动使用其“父类”的成员。

关于OOP和继承的讨论，推荐阅读[这篇知乎回答](https://www.zhihu.com/question/31377101/answer/403757577)，以及[Rust文档中的继承](https://kaisery.github.io/trpl-zh-cn/ch17-01-what-is-oo.html#a继承作为类型系统与代码共享)。

## 参考资料

* [Rust程序设计语言 中文版](https://kaisery.github.io/trpl-zh-cn/)
* [Rust官方文档库](https://www.rust-lang.org/zh-CN/documentation.html)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://rcore.gitbook.io/rust-os-docs/rust-yu-yan-su-cheng.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
