diff --git a/src/appendix/derive.md b/src/appendix/derive.md index 1eeb0493..16260f05 100644 --- a/src/appendix/derive.md +++ b/src/appendix/derive.md @@ -4,11 +4,11 @@ 在本附录中,我们列举了所有标准库存在的 `derive` 特征,每个特征覆盖了以下内容 -* 该特征将会派生什么样的操作符和方法 -* 由 `derive` 提供什么样的特征实现 -* 实现特征对于类型意味着什么 -* 你需要什么条件来实现该特征 -* 特征示例 +- 该特征将会派生什么样的操作符和方法 +- 由 `derive` 提供什么样的特征实现 +- 实现特征对于类型意味着什么 +- 你需要什么条件来实现该特征 +- 特征示例 如果你希望不同于 `derive` 属性所提供的行为,请查阅 [标准库文档](https://doc.rust-lang.org/std/index.html) 中每个特征的细节以了解如何手动实现它们。 @@ -58,7 +58,7 @@ 派生 `Clone` 实现了 `clone` 方法,当为整个的类型实现 `Clone` 时,在该类型的每一部分上都会调用 `clone` 方法。这意味着类型中所有字段或值也必须实现了 `Clone`,这样才能够派生 `Clone` 。 -例如,当在一个切片(slice)上调用 `to_vec` 方法时, `Clone` 是必须的。切片只是一个引用,并不拥有其所包含的实例数据,但是从 `to_vec` 中返回的Vector需要拥有实例数据,因此, `to_vec` 需要在每个元素上调用 `clone` 来逐个复制。因此,存储在切片中的类型必须实现 `Clone`。 +例如,当在一个切片(slice)上调用 `to_vec` 方法时, `Clone` 是必须的。切片只是一个引用,并不拥有其所包含的实例数据,但是从 `to_vec` 中返回的 Vector 需要拥有实例数据,因此, `to_vec` 需要在每个元素上调用 `clone` 来逐个复制。因此,存储在切片中的类型必须实现 `Clone`。 `Copy` 特征允许你通过只拷贝存储在栈上的数据来复制值(浅拷贝),而无需复制存储在堆上的底层数据。查阅 [通过 Copy 复制栈数据](https://course.rs/basic/ownership/ownership.html#拷贝浅拷贝) 的部分来获取有关 `Copy` 的更多信息。 diff --git a/src/appendix/expressions.md b/src/appendix/expressions.md index 3ac77473..55d107bb 100644 --- a/src/appendix/expressions.md +++ b/src/appendix/expressions.md @@ -3,12 +3,14 @@ 在[语句与表达式](https://course.rs/basic/base-type/statement-expression.html)章节中,我们对表达式有过介绍,下面对这些常用表达式进行一一说明。 ### 基本表达式 + ```rust let n = 3; let s = "test"; ``` ### if 表达式 + ```rust fn main() { let var1 = 10; @@ -18,7 +20,7 @@ fn main() { } else { var1 + 10 }; - + println!("{}", var2); } ``` @@ -26,19 +28,21 @@ fn main() { 通过 `if` 表达式将值赋予 `var2`。 你还可以在循环中结合 `continue` 、`break` 来使用: + ```rust let mut v = 0; for i in 1..10 { - v = if i == 9 { - continue - } else { - i + v = if i == 9 { + continue + } else { + i } } println!("{}", v); ``` ### if let 表达式 + ```rust let o = Some(3); let v = if let Some(x) = o { @@ -49,6 +53,7 @@ let v = if let Some(x) = o { ``` ### match 表达式 + ```rust let o = Some(3); let v = match o { @@ -58,6 +63,7 @@ let v = match o { ``` ### loop 表达式 + ```rust let mut n = 0; let v = loop { @@ -69,6 +75,7 @@ let v = loop { ``` ### 语句块 {} + ```rust let mut n = 0; let v = { diff --git a/src/appendix/keywords.md b/src/appendix/keywords.md index bd487f63..2f53b443 100644 --- a/src/appendix/keywords.md +++ b/src/appendix/keywords.md @@ -2,67 +2,66 @@ 下面的列表包含 Rust 中正在使用或者以后会用到的关键字。因此,这些关键字不能被用作标识符(除了[原生标识符](#原生标识符)),包括函数、变量、参数、结构体字段、模块、包、常量、宏、静态值、属性、类型、特征或生命周期。 - ### 目前正在使用的关键字 如下关键字目前有对应其描述的功能。 -* `as` - 强制类型转换,或`use` 和 `extern crate`包和模块引入语句中的重命名 -* `break` - 立刻退出循环 -* `const` - 定义常量或原生常量指针(constant raw pointer) -* `continue` - 继续进入下一次循环迭代 -* `crate` - 链接外部包 -* `dyn` - 动态分发特征对象 -* `else` - 作为 `if` 和 `if let` 控制流结构的 fallback -* `enum` - 定义一个枚举类型 -* `extern` - 链接一个外部包,或者一个宏变量(该变量定义在另外一个包中) -* `false` - 布尔值 `false` -* `fn` - 定义一个函数或 **函数指针类型** (*function pointer type*) -* `for` - 遍历一个迭代器或实现一个 trait 或者指定一个更高级的生命周期 -* `if` - 基于条件表达式的结果来执行相应的分支 -* `impl` - 为结构体或者特征实现具体功能 -* `in` - `for` 循环语法的一部分 -* `let` - 绑定一个变量 -* `loop` - 无条件循环 -* `match` - 模式匹配 -* `mod` - 定义一个模块 -* `move` - 使闭包获取其所捕获项的所有权 -* `mut` - 在引用、原生指针或模式绑定中使用,表明变量是可变的 -* `pub` - 表示结构体字段、`impl` 块或模块的公共可见性 -* `ref` - 通过引用绑定 -* `return` - 从函数中返回 -* `Self` - 实现特征类型的类型别名 -* `self` - 表示方法本身或当前模块 -* `static` - 表示全局变量或在整个程序执行期间保持其生命周期 -* `struct` - 定义一个结构体 -* `super` - 表示当前模块的父模块 -* `trait` - 定义一个特征 -* `true` - 布尔值 `true` -* `type` - 定义一个类型别名或关联类型 -* `unsafe` - 表示不安全的代码、函数、特征或实现 -* `use` - 在当前代码范围内(模块或者花括号对)引入外部的包、模块等 -* `where` - 表示一个约束类型的从句 -* `while` - 基于一个表达式的结果判断是否继续循环 +- `as` - 强制类型转换,或`use` 和 `extern crate`包和模块引入语句中的重命名 +- `break` - 立刻退出循环 +- `const` - 定义常量或原生常量指针(constant raw pointer) +- `continue` - 继续进入下一次循环迭代 +- `crate` - 链接外部包 +- `dyn` - 动态分发特征对象 +- `else` - 作为 `if` 和 `if let` 控制流结构的 fallback +- `enum` - 定义一个枚举类型 +- `extern` - 链接一个外部包,或者一个宏变量(该变量定义在另外一个包中) +- `false` - 布尔值 `false` +- `fn` - 定义一个函数或 **函数指针类型** (_function pointer type_) +- `for` - 遍历一个迭代器或实现一个 trait 或者指定一个更高级的生命周期 +- `if` - 基于条件表达式的结果来执行相应的分支 +- `impl` - 为结构体或者特征实现具体功能 +- `in` - `for` 循环语法的一部分 +- `let` - 绑定一个变量 +- `loop` - 无条件循环 +- `match` - 模式匹配 +- `mod` - 定义一个模块 +- `move` - 使闭包获取其所捕获项的所有权 +- `mut` - 在引用、原生指针或模式绑定中使用,表明变量是可变的 +- `pub` - 表示结构体字段、`impl` 块或模块的公共可见性 +- `ref` - 通过引用绑定 +- `return` - 从函数中返回 +- `Self` - 实现特征类型的类型别名 +- `self` - 表示方法本身或当前模块 +- `static` - 表示全局变量或在整个程序执行期间保持其生命周期 +- `struct` - 定义一个结构体 +- `super` - 表示当前模块的父模块 +- `trait` - 定义一个特征 +- `true` - 布尔值 `true` +- `type` - 定义一个类型别名或关联类型 +- `unsafe` - 表示不安全的代码、函数、特征或实现 +- `use` - 在当前代码范围内(模块或者花括号对)引入外部的包、模块等 +- `where` - 表示一个约束类型的从句 +- `while` - 基于一个表达式的结果判断是否继续循环 ### 保留做将来使用的关键字 如下关键字没有任何功能,不过由 Rust 保留以备将来的应用。 -* `abstract` -* `async` -* `await` -* `become` -* `box` -* `do` -* `final` -* `macro` -* `override` -* `priv` -* `try` -* `typeof` -* `unsized` -* `virtual` -* `yield` +- `abstract` +- `async` +- `await` +- `become` +- `box` +- `do` +- `final` +- `macro` +- `override` +- `priv` +- `try` +- `typeof` +- `unsized` +- `virtual` +- `yield` ### 原生标识符 diff --git a/src/appendix/operators.md b/src/appendix/operators.md index 251094dc..6db959ac 100644 --- a/src/appendix/operators.md +++ b/src/appendix/operators.md @@ -1,6 +1,5 @@ ## 附录 B:运算符与符号 - 该附录包含了 Rust 目前出现过的各种符号,这些符号之前都分散在各个章节中。 ### 运算符 @@ -11,185 +10,183 @@ 表 B-1:运算符 -| 运算符 | 示例 | 解释 | 是否可重载 | -|----------|---------|-------------|---------------| -| `!` | `ident!(...)`, `ident!{...}`, `ident![...]` | 宏展开 | | -| `!` | `!expr` | 按位非或逻辑非 | `Not` | -| `!=` | `var != expr` | 不等比较 | `PartialEq` | -| `%` | `expr % expr` | 算术求余 | `Rem` | -| `%=` | `var %= expr` | 算术求余与赋值 | `RemAssign` | -| `&` | `&expr`, `&mut expr` | 借用 | | -| `&` | `&type`, `&mut type`, `&'a type`, `&'a mut type` | 借用指针类型 | | -| `&` | `expr & expr` | 按位与 | `BitAnd` | -| `&=` | `var &= expr` | 按位与及赋值 | `BitAndAssign` | -| `&&` | `expr && expr` | 逻辑与 | | -| `*` | `expr * expr` | 算术乘法 | `Mul` | -| `*=` | `var *= expr` | 算术乘法与赋值 | `MulAssign` | -| `*` | `*expr` | 解引用 | | -| `*` | `*const type`, `*mut type` | 原生指针 | | -| `+` | `trait + trait`, `'a + trait` | 复合类型限制 | | -| `+` | `expr + expr` | 算术加法 | `Add` | -| `+=` | `var += expr` | 算术加法与赋值 | `AddAssign` | -| `,` | `expr, expr` | 参数以及元素分隔符 | | -| `-` | `- expr` | 算术取负 | `Neg` | -| `-` | `expr - expr` | 算术减法| `Sub` | -| `-=` | `var -= expr` | 算术减法与赋值 | `SubAssign` | -| `->` | `fn(...) -> type`, |...| -> type | 函数与闭包,返回类型 | | -| `.` | `expr.ident` | 成员访问 | | -| `..` | `..`, `expr..`, `..expr`, `expr..expr` | 右半开区间 | PartialOrd | -| `..=` | `..`, `expr..`, `..expr`, `expr..expr` | 闭合区间 | PartialOrd | -| `..` | `..expr` | 结构体更新语法 | | -| `..` | `variant(x, ..)`, `struct_type { x, .. }` | “代表剩余部分”的模式绑定 | | -| `...` | `expr...expr` | (不推荐使用,用`..=`替代) 闭合区间 | | -| `/` | `expr / expr` | 算术除法 | `Div` | -| `/=` | `var /= expr` | 算术除法与赋值 | `DivAssign` | -| `:` | `pat: type`, `ident: type` | 约束 | | -| `:` | `ident: expr` | 结构体字段初始化 | | -| `:` | `'a: loop {...}` | 循环标志 | | -| `;` | `expr;` | 语句和语句结束符 | | -| `;` | `[...; len]` | 固定大小数组语法的部分 | | -| `<<` | `expr << expr` |左移 | `Shl` | -| `<<=` | `var <<= expr` | 左移与赋值| `ShlAssign` | -| `<` | `expr < expr` | 小于比较 | `PartialOrd` | -| `<=` | `expr <= expr` | 小于等于比较 | `PartialOrd` | -| `=` | `var = expr`, `ident = type` | 赋值/等值 | | -| `==` | `expr == expr` | 等于比较 | `PartialEq` | -| `=>` | `pat => expr` | 匹配分支语法的部分 | | -| `>` | `expr > expr` | 大于比较 | `PartialOrd` | -| `>=` | `expr >= expr` | 大于等于比较 | `PartialOrd` | -| `>>` | `expr >> expr` | 右移 | `Shr` | -| `>>=` | `var >>= expr` | 右移与赋值 | `ShrAssign` | -| `@` | `ident @ pat` | 模式绑定 | | -| `^` | `expr ^ expr` | 按位异或 | `BitXor` | -| `^=` | `var ^= expr` | 按位异或与赋值 | `BitXorAssign` | -| | | pat | pat | 模式匹配中的多个可选条件 | | -| | | expr | expr | 按位或 | `BitOr` | -| |= | var |= expr | 按位或与赋值 | `BitOrAssign` | -| || | expr || expr | 逻辑或 | | -| `?` | `expr?` | 错误传播 | | - +| 运算符 | 示例 | 解释 | 是否可重载 | +| ------------------------- | ------------------------------------------------------- | ---------------------------------- | -------------- | +| `!` | `ident!(...)`, `ident!{...}`, `ident![...]` | 宏展开 | | +| `!` | `!expr` | 按位非或逻辑非 | `Not` | +| `!=` | `var != expr` | 不等比较 | `PartialEq` | +| `%` | `expr % expr` | 算术求余 | `Rem` | +| `%=` | `var %= expr` | 算术求余与赋值 | `RemAssign` | +| `&` | `&expr`, `&mut expr` | 借用 | | +| `&` | `&type`, `&mut type`, `&'a type`, `&'a mut type` | 借用指针类型 | | +| `&` | `expr & expr` | 按位与 | `BitAnd` | +| `&=` | `var &= expr` | 按位与及赋值 | `BitAndAssign` | +| `&&` | `expr && expr` | 逻辑与 | | +| `*` | `expr * expr` | 算术乘法 | `Mul` | +| `*=` | `var *= expr` | 算术乘法与赋值 | `MulAssign` | +| `*` | `*expr` | 解引用 | | +| `*` | `*const type`, `*mut type` | 原生指针 | | +| `+` | `trait + trait`, `'a + trait` | 复合类型限制 | | +| `+` | `expr + expr` | 算术加法 | `Add` | +| `+=` | `var += expr` | 算术加法与赋值 | `AddAssign` | +| `,` | `expr, expr` | 参数以及元素分隔符 | | +| `-` | `- expr` | 算术取负 | `Neg` | +| `-` | `expr - expr` | 算术减法 | `Sub` | +| `-=` | `var -= expr` | 算术减法与赋值 | `SubAssign` | +| `->` | `fn(...) -> type`, |...| -> type | 函数与闭包,返回类型 | | +| `.` | `expr.ident` | 成员访问 | | +| `..` | `..`, `expr..`, `..expr`, `expr..expr` | 右半开区间 | PartialOrd | +| `..=` | `..`, `expr..`, `..expr`, `expr..expr` | 闭合区间 | PartialOrd | +| `..` | `..expr` | 结构体更新语法 | | +| `..` | `variant(x, ..)`, `struct_type { x, .. }` | “代表剩余部分”的模式绑定 | | +| `...` | `expr...expr` | (不推荐使用,用`..=`替代) 闭合区间 | | +| `/` | `expr / expr` | 算术除法 | `Div` | +| `/=` | `var /= expr` | 算术除法与赋值 | `DivAssign` | +| `:` | `pat: type`, `ident: type` | 约束 | | +| `:` | `ident: expr` | 结构体字段初始化 | | +| `:` | `'a: loop {...}` | 循环标志 | | +| `;` | `expr;` | 语句和语句结束符 | | +| `;` | `[...; len]` | 固定大小数组语法的部分 | | +| `<<` | `expr << expr` | 左移 | `Shl` | +| `<<=` | `var <<= expr` | 左移与赋值 | `ShlAssign` | +| `<` | `expr < expr` | 小于比较 | `PartialOrd` | +| `<=` | `expr <= expr` | 小于等于比较 | `PartialOrd` | +| `=` | `var = expr`, `ident = type` | 赋值/等值 | | +| `==` | `expr == expr` | 等于比较 | `PartialEq` | +| `=>` | `pat => expr` | 匹配分支语法的部分 | | +| `>` | `expr > expr` | 大于比较 | `PartialOrd` | +| `>=` | `expr >= expr` | 大于等于比较 | `PartialOrd` | +| `>>` | `expr >> expr` | 右移 | `Shr` | +| `>>=` | `var >>= expr` | 右移与赋值 | `ShrAssign` | +| `@` | `ident @ pat` | 模式绑定 | | +| `^` | `expr ^ expr` | 按位异或 | `BitXor` | +| `^=` | `var ^= expr` | 按位异或与赋值 | `BitXorAssign` | +| | | pat | pat | 模式匹配中的多个可选条件 | | +| | | expr | expr | 按位或 | `BitOr` | +| |= | var |= expr | 按位或与赋值 | `BitOrAssign` | +| || | expr || expr | 逻辑或 | | +| `?` | `expr?` | 错误传播 | | ### 非运算符符号 表 B-2:独立语法 -| 符号 | 解释 | -|--------|-------------| -| `'ident` | 生命周期名称或循环标签 | -| `...u8`, `...i32`, `...f64`, `...usize`, 等 | 指定类型的数值常量 | -| `"..."` | 字符串常量 | -| `r"..."`, `r#"..."#`, `r##"..."##`, etc. | 原生字符串, 未转义字符 | -| `b"..."` | 将 `&str` 转换成 `&[u8; N]` 类型的数组 | -| `br"..."`, `br#"..."#`, `br##"..."##`, 等 | 原生字节字符串,原生和字节字符串字面值的结合 | -| `'...'` | Char字符 | -| `b'...'` | ASCII字节 | -| |...| expr | 闭包 | -| `!` | 代表总是空的类型,用于发散函数(无返回值函数) | -| `_` | 模式绑定中表示忽略的意思;也用于增强整型字面值的可读性 | +| 符号 | 解释 | +| ------------------------------------------- | ------------------------------------------------------ | +| `'ident` | 生命周期名称或循环标签 | +| `...u8`, `...i32`, `...f64`, `...usize`, 等 | 指定类型的数值常量 | +| `"..."` | 字符串常量 | +| `r"..."`, `r#"..."#`, `r##"..."##`, etc. | 原生字符串, 未转义字符 | +| `b"..."` | 将 `&str` 转换成 `&[u8; N]` 类型的数组 | +| `br"..."`, `br#"..."#`, `br##"..."##`, 等 | 原生字节字符串,原生和字节字符串字面值的结合 | +| `'...'` | Char 字符 | +| `b'...'` | ASCII 字节 | +| |...| expr | 闭包 | +| `!` | 代表总是空的类型,用于发散函数(无返回值函数) | +| `_` | 模式绑定中表示忽略的意思;也用于增强整型字面值的可读性 | 表 B-3 展示了模块和对象调用路径的语法。 表 B-3:路径相关语法 -| 符号 | 解释 | -|--------|-------------| -| `ident::ident` | 命名空间路径 | -| `::path` | 从当前的包的根路径开始的相对路径 | -| `self::path` | 与当前模块相对的路径(如一个显式相对路径)| -| `super::path` | 与父模块相对的路径 | -| `type::ident`, `::ident` | 关联常量、关联函数、关联类型 | -| `::...` | 不可以被直接命名的关联项类型(如 `<&T>::...`,`<[T]>::...`, 等) | -| `trait::method(...)` | 使用特征名进行方法调用,以消除方法调用的二义性 | -| `type::method(...)` | 使用类型名进行方法调用, 以消除方法调用的二义性 | -| `::method(...)` | 将类型转换为特征,再进行方法调用,以消除方法调用的二义性 | - +| 符号 | 解释 | +| --------------------------------------- | ----------------------------------------------------------------- | +| `ident::ident` | 命名空间路径 | +| `::path` | 从当前的包的根路径开始的相对路径 | +| `self::path` | 与当前模块相对的路径(如一个显式相对路径) | +| `super::path` | 与父模块相对的路径 | +| `type::ident`, `::ident` | 关联常量、关联函数、关联类型 | +| `::...` | 不可以被直接命名的关联项类型(如 `<&T>::...`,`<[T]>::...`, 等) | +| `trait::method(...)` | 使用特征名进行方法调用,以消除方法调用的二义性 | +| `type::method(...)` | 使用类型名进行方法调用, 以消除方法调用的二义性 | +| `::method(...)` | 将类型转换为特征,再进行方法调用,以消除方法调用的二义性 | 表 B-4 展示了使用泛型参数时用到的符号。 表 B-4:泛型 -| 符号 | 解释 | -|--------|-------------| -| `path<...>` | 为一个类型中的泛型指定具体参数(如 `Vec`) | -| `path::<...>`, `method::<...>` | 为一个泛型、函数或表达式中的方法指定具体参数,通常指双冒号(turbofish)(如 `"42".parse::()`)| -| `fn ident<...> ...` | 泛型函数定义 | -| `struct ident<...> ...` | 泛型结构体定义 | -| `enum ident<...> ...` | 泛型枚举定义 | -| `impl<...> ...` | 实现泛型 | -| `for<...> type` | 高阶生命周期限制 | -| `type` | 泛型,其一个或多个相关类型必须被指定为特定类型(如 `Iterator`)| +| 符号 | 解释 | +| ------------------------------ | ------------------------------------------------------------------------------------------------- | +| `path<...>` | 为一个类型中的泛型指定具体参数(如 `Vec`) | +| `path::<...>`, `method::<...>` | 为一个泛型、函数或表达式中的方法指定具体参数,通常指双冒号(turbofish)(如 `"42".parse::()`) | +| `fn ident<...> ...` | 泛型函数定义 | +| `struct ident<...> ...` | 泛型结构体定义 | +| `enum ident<...> ...` | 泛型枚举定义 | +| `impl<...> ...` | 实现泛型 | +| `for<...> type` | 高阶生命周期限制 | +| `type` | 泛型,其一个或多个相关类型必须被指定为特定类型(如 `Iterator`) | 表 B-5 展示了使用特征约束来限制泛型参数的符号。 表 B-5:特征约束 -| 符号 | 解释 | -|--------|-------------| -| `T: U` | 泛型参数 `T`需实现`U`类型 | -| `T: 'a` | 泛型 `T` 的生命周期必须长于 `'a`(意味着该类型不能传递包含生命周期短于 `'a` 的任何引用)| -| `T : 'static` | 泛型 T只能使用声明周期为'static的引用 | -| `'b: 'a` |生命周期`'b`必须长于生命周期`'a` | -| `T: ?Sized` | 使用一个不定大小的泛型类型 | -| `'a + trait`, `trait + trait` | 多个类型组成的复合类型限制 | +| 符号 | 解释 | +| ----------------------------- | ---------------------------------------------------------------------------------------- | +| `T: U` | 泛型参数 `T`需实现`U`类型 | +| `T: 'a` | 泛型 `T` 的生命周期必须长于 `'a`(意味着该类型不能传递包含生命周期短于 `'a` 的任何引用) | +| `T : 'static` | 泛型 T 只能使用声明周期为'static 的引用 | +| `'b: 'a` | 生命周期`'b`必须长于生命周期`'a` | +| `T: ?Sized` | 使用一个不定大小的泛型类型 | +| `'a + trait`, `trait + trait` | 多个类型组成的复合类型限制 | 表 B-6 展示了宏以及在一个对象上定义属性的符号。 表 B-6:宏与属性 -| 符号 | 解释 | -|--------|-------------| -| `#[meta]` | 外部属性 | -| `#![meta]` | 内部属性 | -| `$ident` | 宏替换 | -| `$ident:kind` | 宏捕获 | -| `$(…)…` | 宏重复 | -| `ident!(...)`, `ident!{...}`, `ident![...]` | 宏调用 | +| 符号 | 解释 | +| ------------------------------------------- | -------- | +| `#[meta]` | 外部属性 | +| `#![meta]` | 内部属性 | +| `$ident` | 宏替换 | +| `$ident:kind` | 宏捕获 | +| `$(…)…` | 宏重复 | +| `ident!(...)`, `ident!{...}`, `ident![...]` | 宏调用 | 表 B-7 展示了写注释的符号。 表 B-7:注释 -| 符号 | 注释 | -|--------|-------------| -| `//` | 行注释 | -| `//!` | 内部行(hang)文档注释 | -| `///` | 外部行文档注释 | -| `/*...*/` | 块注释 | -| `/*!...*/` | 内部块文档注释 | -| `/**...*/` | 外部块文档注释 | +| 符号 | 注释 | +| ---------- | -------------------- | +| `//` | 行注释 | +| `//!` | 内部行(hang)文档注释 | +| `///` | 外部行文档注释 | +| `/*...*/` | 块注释 | +| `/*!...*/` | 内部块文档注释 | +| `/**...*/` | 外部块文档注释 | 表 B-8 展示了出现在使用元组时的符号。 表 B-8:元组 -| 符号 | 解释 | -|--------|-------------| -| `()` | 空元组(亦称单元),即是字面值也是类型 | -| `(expr)` | 括号表达式 | -| `(expr,)` | 单一元素元组表达式 | -| `(type,)` | 单一元素元组类型 | -| `(expr, ...)` | 元组表达式 | -| `(type, ...)` | 元组类型 | -| `expr(expr, ...)` | 函数调用表达式;也用于初始化元组结构体 `struct` 以及元组枚举 `enum` 变体 | -| `expr.0`, `expr.1`, etc. | 元组索引 | +| 符号 | 解释 | +| ------------------------ | ------------------------------------------------------------------------ | +| `()` | 空元组(亦称单元),即是字面值也是类型 | +| `(expr)` | 括号表达式 | +| `(expr,)` | 单一元素元组表达式 | +| `(type,)` | 单一元素元组类型 | +| `(expr, ...)` | 元组表达式 | +| `(type, ...)` | 元组类型 | +| `expr(expr, ...)` | 函数调用表达式;也用于初始化元组结构体 `struct` 以及元组枚举 `enum` 变体 | +| `expr.0`, `expr.1`, etc. | 元组索引 | 表 B-9 展示了使用大括号的上下文。 表 B-9:大括号 -| 符号 | 解释 | -|---------|-------------| -| `{...}` | 代码块表达式 | -| `Type {...}` | 结构体字面值 | +| 符号 | 解释 | +| ------------ | ------------ | +| `{...}` | 代码块表达式 | +| `Type {...}` | 结构体字面值 | 表 B-10 展示了使用方括号的上下文。 表 B-10:方括号 -| 符号 | 解释 | -|---------|-------------| -| `[...]` | 数组 | -| `[expr; len]` | 数组里包含`len`个`expr` | -| `[type; len]` | 数组里包含了`len`个`type`类型的对象| -| `expr[expr]` | 集合索引。 重载(`Index`, `IndexMut`) | +| 符号 | 解释 | +| -------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | +| `[...]` | 数组 | +| `[expr; len]` | 数组里包含`len`个`expr` | +| `[type; len]` | 数组里包含了`len`个`type`类型的对象 | +| `expr[expr]` | 集合索引。 重载(`Index`, `IndexMut`) | | `expr[..]`, `expr[a..]`, `expr[..b]`, `expr[a..b]` | 集合索引,也称为集合切片,索引要实现以下特征中的其中一个:`Range`,`RangeFrom`,`RangeTo` 或 `RangeFull` | diff --git a/src/appendix/rust-version.md b/src/appendix/rust-version.md index f6c3abcd..8544f7ba 100644 --- a/src/appendix/rust-version.md +++ b/src/appendix/rust-version.md @@ -1,7 +1,8 @@ # 附录 F:Rust 版本发布 ## Rust 版本说明 -早在第一章,我们见过 `cargo new` 在 *Cargo.toml* 中增加了一些有关 `edition` 的元数据。本附录将解释其意义! + +早在第一章,我们见过 `cargo new` 在 _Cargo.toml_ 中增加了一些有关 `edition` 的元数据。本附录将解释其意义! 与其它语言相比,Rust 的更新迭代较为频繁(得益于精心设计过的发布流程以及 Rust 语言开发者团队管理): @@ -14,10 +15,9 @@ - 对于一般的用户,edition 的发布会告诉这些用户:Rust 语言相比上次大版本发布,有了重大的改进,值得一看 - 对于 Rust 语言开发者,可以让他们的工作成果更快的被世人所知,不必锦衣夜行 - 在本文档编写时,Rust 已经有三个版本:Rust 2015、2018、2021。本书基于 `Rust 2021 edition` 编写。 -*Cargo.toml* 中的 `edition` 字段表明代码应该使用哪个版本编译。如果该字段不存在,其默认为 `2021` 以提供后向兼容性。 +_Cargo.toml_ 中的 `edition` 字段表明代码应该使用哪个版本编译。如果该字段不存在,其默认为 `2021` 以提供后向兼容性。 每个项目都可以选择不同于默认的 `Rust 2021 edition` 的版本。这样,版本可能会包含不兼容的修改,比如新版本中新增的关键字可能会与老代码中的标识符冲突并导致错误。不过,除非你选择应用这些修改,否则旧代码依然能够被编译,即便你升级了编译器版本。 @@ -27,7 +27,6 @@ 请查看 [Edition Guide](https://rust-lang-nursery.github.io/edition-guide/) 了解更多细节,这是一个完全介绍版本的书籍,包括如何通过 `cargo fix` 自动将代码迁移到新版本。 - ## Rust 自身开发流程 本附录介绍 Rust 语言自身是如何开发的以及这如何影响作为 Rust 开发者的你。 @@ -40,11 +39,11 @@ ### Choo, Choo! ~~ 小火车发布流程启动 -开发 Rust 语言是基于一个**火车时刻表**来进行的:所有的开发工作在 Master 分支上完成,但是发布就像火车时刻表一样,拥有不同的时间,发布采用的软件发布列车模型,被用于思科IOS和等其它软件项目。Rust 有三个 **发布通道**(*release channel*): +开发 Rust 语言是基于一个**火车时刻表**来进行的:所有的开发工作在 Master 分支上完成,但是发布就像火车时刻表一样,拥有不同的时间,发布采用的软件发布列车模型,被用于思科 IOS 和等其它软件项目。Rust 有三个 **发布通道**(_release channel_): -* Nightly -* Beta -* Stable(稳定版) +- Nightly +- Beta +- Stable(稳定版) 大部分 Rust 开发者主要采用稳定版通道,不过希望实验新功能的开发者可能会使用 nightly 或 beta 版。 @@ -115,13 +114,14 @@ Rust 每 6 周发布一个版本,如时钟般准确。如果你知道了某个 ### Rustup 和 Rust Nightly 的职责 #### 安装 Rust Nightly 版本 + Rustup 使得改变不同发布通道的 Rust 更为简单,其在全局或分项目的层次工作。其默认会安装稳定版 Rust。例如为了安装 nightly: ```text $ rustup install nightly ``` -你会发现 `rustup` 也安装了所有的 **工具链**(*toolchains*, Rust 和其相关组件)。如下是一位作者的 Windows 计算机上的例子: +你会发现 `rustup` 也安装了所有的 **工具链**(_toolchains_, Rust 和其相关组件)。如下是一位作者的 Windows 计算机上的例子: ```powershell > rustup toolchain list @@ -130,7 +130,8 @@ beta-x86_64-pc-windows-msvc nightly-x86_64-pc-windows-msvc ``` -#### 在指定目录使用Rust Nightly +#### 在指定目录使用 Rust Nightly + 如你所见,默认是稳定版。大部分 Rust 用户在大部分时间使用稳定版。你可能也会这么做,不过如果你关心最新的功能,可以为特定项目使用 nightly 版。为此,可以在项目目录使用 `rustup override` 来设置当前目录 `rustup` 使用 nightly 工具链: ```text @@ -138,7 +139,7 @@ $ cd ~/projects/needs-nightly $ rustup override set nightly ``` -现在,每次在 *~/需要nightly的项目/*下(在项目的根目录下,也就是 `Cargo.toml` 所在的目录) 调用 `rustc` 或 `cargo`,`rustup` 会确保使用 nightly 版 Rust。在你有很多 Rust 项目时大有裨益! +现在,每次在 *~/需要 nightly 的项目/*下(在项目的根目录下,也就是 `Cargo.toml` 所在的目录) 调用 `rustc` 或 `cargo`,`rustup` 会确保使用 nightly 版 Rust。在你有很多 Rust 项目时大有裨益! ### RFC 过程和团队 diff --git a/src/appendix/rust-versions/1.58.md b/src/appendix/rust-versions/1.58.md index 7f09b614..1a747642 100644 --- a/src/appendix/rust-versions/1.58.md +++ b/src/appendix/rust-versions/1.58.md @@ -1,12 +1,13 @@ -# Rust 新版解读 | 1.58 | 重点: 格式化字符串捕获环境中的值 +# Rust 新版解读 | 1.58 | 重点: 格式化字符串捕获环境中的值 众所周知,Rust 小版本发布非常频繁,6 周就发布一次,因此通常不会有特别值得普通用户关注的内容,但是这次 1.58 版本不同,新增了(stable 化了)一个非常好用的功能: **在格式化字符串时捕获环境中的值**。 -> Rust 1.58 官方 release doc: [Announcing Rust 1.58.0 | Rust Blog](https://blog.rust-lang.org/2022/01/13/Rust-1.58.0.html) +> Rust 1.58 官方 release doc: [Announcing Rust 1.58.0 | Rust Blog](https://blog.rust-lang.org/2022/01/13/Rust-1.58.0.html) ## 在格式化字符串时捕获环境中的值 在以前,想要输出一个函数的返回值,你需要这么做: + ```rust fn get_person() -> String { String::from("sunface") @@ -18,7 +19,9 @@ fn main() { println!("Hello, {person}!", person = p); } ``` + 问题倒也不大,但是一旦格式化字符串长了后,就会非常冗余,而在 1.58 后,我们可以这么写: + ```rust fn get_person() -> String { String::from("sunface") @@ -28,16 +31,20 @@ fn main() { println!("Hello, {person}!"); } ``` + 是不是清晰、简洁了很多?甚至还可以将环境中的值用于格式化参数: + ```rust let (width, precision) = get_format(); for (name, score) in get_scores() { println!("{name}: {score:width$.precision$}"); } ``` + 但也有局限,它只能捕获普通的变量,对于更复杂的类型(例如表达式),可以先将它赋值给一个变量或使用以前的 `name = expression` 形式的格式化参数。 -目前除了 `panic!` 外,其它接收格式化参数的宏,都可以使用新的特性。对于 `panic!` 而言,如果还在使用 `2015版本` 或 `2018版本` 版本 ,那 `panic!("{ident}")` 依然会被当成 正常的字符串来处理,同时编译器会给予 `warn` 提示。而对于 `2021版本` ,则可以正常使用: +目前除了 `panic!` 外,其它接收格式化参数的宏,都可以使用新的特性。对于 `panic!` 而言,如果还在使用 `2015版本` 或 `2018版本` 版本 ,那 `panic!("{ident}")` 依然会被当成 正常的字符串来处理,同时编译器会给予 `warn` 提示。而对于 `2021版本` ,则可以正常使用: + ```rust fn get_person() -> String { String::from("sunface") @@ -49,6 +56,7 @@ fn main() { ``` 输出: + ```console thread 'main' panicked at 'Hello, sunface!', src/main.rs:6:5 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace @@ -57,6 +65,7 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace ## 比 unwrap 更危险的 unwrap_unchecked 在 1.58 中为 `Option` 和 `Result` 新增了 `unwrap_unchecked` 方法,与 `unwrap` 遇到错误或者空值直接 `panic` 不同,`unwrap_unchecked` 遇到错误时处理方式糟糕的多: + ```rust fn get_num() -> Option { None @@ -69,13 +78,14 @@ fn main() { ``` 输出如下: + ```console zsh: segmentation fault cargo run ``` -嗯,段错误了,对比下 `panic`,有一种泪流满面的冲动:我要这不安全的方法何用? +嗯,段错误了,对比下 `panic`,有一种泪流满面的冲动:我要这不安全的方法何用? 其实,还真有些用: -- 想要较小的可执行文件时(嵌入式,WASM等),该方法就可以大显身手。因为 `panic` 会导致[二进制可执行文件变大不少](https://zhuanlan.zhihu.com/p/445465092) +- 想要较小的可执行文件时(嵌入式,WASM 等),该方法就可以大显身手。因为 `panic` 会导致[二进制可执行文件变大不少](https://zhuanlan.zhihu.com/p/445465092) - 它还可以提高一点性能, 因为编译器可能无法优化掉 `unwrap` 的指令分支, 虽然它只会增加区区几条分支预测指令 diff --git a/src/appendix/rust-versions/1.59.md b/src/appendix/rust-versions/1.59.md index eaf9570b..03f4891c 100644 --- a/src/appendix/rust-versions/1.59.md +++ b/src/appendix/rust-versions/1.59.md @@ -1,10 +1,13 @@ # Rust 新版解读 | 1.59 | 重点: 内联汇编、解构式赋值 + Rust 团队于今天凌晨( 2022-02-25 )发布了最新的 1.59 版本,其中最引人瞩目的特性应该就是支持在代码中内联汇编了,一起来看看。 ## 内联汇编( inline assembly ) + 该特性对于需要底层控制的应用非常有用,例如想要控制底层执行、访问特定的机器指令等。 例如,如果目标平台是 `x86-64` 时,你可以这么写: + ```rust use std::arch::asm; @@ -35,7 +38,9 @@ assert_eq!(x, 4 * 6); 如果大家希望深入了解,可以看官方的 [Reference](https://doc.rust-lang.org/nightly/reference/inline-assembly.html) 文档,同时在 [Rust Exercise](https://zh.exercise.rs/unsafe/inline-asm) 中提供了更多的示例(目前正在翻译中..)。 ## 解构式赋值( Destructuring assignments) + 现在你可以在赋值语句的左式中使用元组、切片和结构体模式了。 + ```rust let (a, b, c, d, e); @@ -51,7 +56,9 @@ assert_eq!([1, 2, 1, 4, 5], [a, b, c, d, e]); ## const 泛型 #### 为参数设置默认值 + 现在我们可以为 const 泛型参数设置默认值: + ```rust struct ArrayStorage { arr: [T; N], @@ -67,7 +74,9 @@ impl ArrayStorage { ``` #### 取消参数顺序的限制 + 在之前版本中,类型参数必须要在所有的 const 泛型参数之前,现在,这个限制被放宽了,例如你可以这样交替排列它们: + ```rust fn cartesian_product< T, const N: usize, @@ -82,9 +91,11 @@ where ``` ## 减少二进制文件体积:删除 debug 信息 + 对于受限的环境来说,减少编译出的二进制文件体积是非常重要的。 在之前,我们可以在二进制文件创建后,手动的来完成。现在 cargo 和 rustc 支持在链接( linked )后就删除 debug 信息,在 `Cargo.toml` 中新增以下配置: + ```toml [profile.release] strip = "debuginfo" @@ -99,17 +110,20 @@ strip = "debuginfo" - 最后 `opt-level = "z"` : 1,857,680 bytes 如果是 WASM,还可以使用以下配置进一步减少体积: + ```toml [package.metadata.wasm-pack.profile.release] wasm-opt = ['-Os'] ``` -[github上一个开源仓库](https://github.com/rsadsb/adsb_deku/blob/master/CHANGELOG.md#unreleased)也证明了这一点,总体来看,这个配置的效果是非常显著的! +[github 上一个开源仓库](https://github.com/rsadsb/adsb_deku/blob/master/CHANGELOG.md#unreleased)也证明了这一点,总体来看,这个配置的效果是非常显著的! ## 默认关闭增量编译 + 1.59.0 版本默认关闭了增量编译的功能(你可以通过环境变量显式地启用:`RUSTC_FORCE_INCREMENTAL=1` ),这会降低已知 Bug [#94124](https://github.com/rust-lang/rust/issues/94124) 的影响,该 Bug 会导致增量编译过程中的反序列化错误和 `panic`。 不过大家也不用担心,这个 Bug 会在 1.60.0 版本修复,也就是 6 周后,增量编译会重新设置为默认开启,如果没有意外的话 :) ## 稳定化的 API 列表 + 一些方法和特征实现现在已经可以 stable 中使用,具体见[官方发布说明](https://blog.rust-lang.org/2022/02/24/Rust-1.59.0.html#stabilized-apis) diff --git a/src/appendix/rust-versions/intro.md b/src/appendix/rust-versions/intro.md index efa44c6d..0a9b1385 100644 --- a/src/appendix/rust-versions/intro.md +++ b/src/appendix/rust-versions/intro.md @@ -1,2 +1,3 @@ # 附录 G:Rust 更新版本列表 + 本目录包含了 Rust 历次版本更新的重要内容解读,需要注意,每个版本实际更新的内容要比这里记录的更多,全部内容请访问每节开头的官方链接查看。