这是用户在 2024-7-30 14:57 为 https://cheats.rs/ 保存的双语快照页面,由 沉浸式翻译 提供双语支持。了解如何保存?
Fork me on GitHub

Rust Language Cheat Sheet
Rust 语言速查表
28. July 2024 2024 年 7 月 28 日

Contains clickable links to The Book BK, Rust by Example EX, Std Docs STD, Nomicon NOM, Reference REF.
包含指向《The Book BK 》、《Rust by Example EX 》、标准文档 STD 、Nomicon NOM 、参考资料 REF 的可点击链接。

Clickable symbols

BK The Book.
EX Rust by Example.
STD Standard Library (API).
NOM Nomicon.
REF Reference.
RFC Official RFC documents.
🔗 The internet.
On this page, above.
On this page, below.

Other symbols

🗑️ Largely deprecated.
'18 Has minimum edition requirement.
🚧 Requires Rust nightly (or is incomplete).
🛑 Intentionally wrong example or pitfall.
🝖 Slightly esoteric, rarely used or advanced.
🔥 Something with outstanding utility.
↪  The parent item expands to
💬 Opinionated.
? Is missing good link or explanation.

Font Ligatures (..=, =>) Night Mode 💡
字体连字( ..=, => )夜间模式 💡

Language Constructs 语言结构

Behind the Scenes 幕后花絮

Memory Layout 内存布局

Misc 杂项

Standard Library 标准库

Tooling 工具化

Working with Types 处理类型

Coding Guides 编码指南

Hello, Rust! 你好,Rust!url

If you are new to Rust, or if you want to try the things below:
如果您是 Rust 的新手,或者想尝试以下内容:

fn main() {
    println!("Hello, world!");
}
Service provided by play.rust-lang.org 🔗

Things Rust does measurably really well
Rust 在可衡量的方面做得非常好

  • Compiled code about same performance as C / C++, and excellent memory and energy efficiency.
    编译后的代码性能与 C / C ++相当,并且具有出色的内存和能源效率。
  • Can avoid 70% of all safety issues present in C / C++, and most memory issues.
    可以避免 C / C++ 中存在的 70% 的所有安全问题,以及大多数内存问题。
  • Strong type system prevents data races, brings 'fearless concurrency' (amongst others).
    强大的类型系统可以防止数据竞争,实现“无畏并发”(等等)。
  • Seamless C interop, and dozens of supported platforms (based on LLVM).
    无缝的 C 互操作性,支持数十种平台(基于 LLVM)。
  • "Most loved or admired language" for 4 5 6 7 8 years in a row. 🤷‍♀️
    连续 4 年至 8 年被最喜爱或钦佩的语言。🤷‍♀️
  • Modern tooling: cargo (builds just work), clippy (700+ code quality lints), rustup (easy toolchain mgmt).
    现代工具: cargo (构建只需工作), clippy (700+ 代码质量检查), rustup (简单的工具链管理)。

Points you might run into
可能遇到的问题

  • Steep learning curve;1 compiler enforcing (esp. memory) rules that would be "best practices" elsewhere.
    陡峭的学习曲线; 1 编译器强制执行(尤其是内存)规则,在其他地方可能是“最佳实践”。
  • Missing Rust-native libs in some domains, target platforms (esp. embedded), IDE features.1
    在某些领域、目标平台(尤其是嵌入式)和 IDE 功能中缺少 Rust 本机库。 1
  • Longer compile times than "similar" code in other languages.1
    编译时间比其他语言中的“相似”代码长。 1
  • Careless (use of unsafe in) libraries can secretly break safety guarantees.
    使用 unsafe 库可能会悄悄破坏安全保证。
  • No formal language specification, 🔗 can prevent legal use in some domains (aviation, medical, …). 🔗
    没有正式的语言规范, 🔗 可能会在某些领域(航空、医疗等)阻止合法使用。 🔗
  • Rust Foundation may offensively use their IP to affect 'Rust' projects (e.g, forbid names, impose policies). 🔗🔗2
    Rust 基金会可能会进攻性地使用他们的知识产权来影响 'Rust' 项目(例如,禁止名称,实施政策)。 🔗 🔗 2

1 Compare Rust Survey.
1 Rust 调查比较。

2 Avoiding their marks (e.g, in your name, URL, logo, dress) is probably sufficient.
2 避免他们的标记(例如,在您的名称、URL、标志、服装中)可能就足够了。

Download 下载

  • Get installer from rustup.rs (highly recommended)🔥
    从 rustup.rs 获取安装程序(强烈推荐) 🔥

IDEs IDE(集成开发环境)

Modular Beginner Resources
模块化初学者资源

  • Tour of Rust - Live code and explanations, side by side.
    Rust 之旅 - 实时代码和解释,并排显示。
  • Rust in Easy English - 60+ concepts, simple English, example-driven.
    Rust 简单英语 - 60 多个概念,简单英语,以示例驱动。

In addition, have a look at the usual suspects: BK EX STD
此外,看看通常的嫌疑人: BK EX STD

Opinion 💬 — If you have never seen or used any Rust it might be good to visit one of the links above before continuing; the next chapter might feel a bit terse otherwise.
意见 💬 — 如果您从未见过或使用过 Rust,最好在继续之前访问上面的链接之一;否则下一章可能会感觉有点仓促。

Data Structures 数据结构url

Data types and memory locations defined via keywords.
数据类型和内存位置通过关键字定义。

Example 示例Explanation 解释
struct S {}Define a struct BK EX STD REF with named fields.
使用具有命名字段的结构 BK EX STD REF
     struct S { x: T }Define struct with named field x of type T.
使用类型为 T 定义具有命名字段 x 的结构。
     struct S ​(T);Define "tupled" struct with numbered field .0 of type T.
使用编号字段 .0 定义“tupled”结构,类型为 T
     struct S;Define zero sized NOM unit struct. Occupies no space, optimized away.
定义零大小的 NOM 单位结构。不占用空间,被优化掉。
enum E {}Define an enum, BK EX REF c. algebraic data types, tagged unions.
定义一个枚举, BK EX REF c。代数数据类型,标记联合。
     enum E { A, B(), C {} }Define variants of enum; can be unit- A, tuple- B ​() and struct-like C{}.
定义枚举的变体;可以是单元- A ,元组- B () 和类似结构体的 C{}
     enum E { A = 1 }Enum with explicit discriminant values, REF e.g., for FFI.
具有显式标记值的枚举, REF 例如,用于 FFI。
     enum E {}Enum w/o variants is uninhabited, REF can't be created, c. 'never' 🝖
枚举没有变体是不可居住的, REF 无法创建,c. 'never' 🝖
union U {}Unsafe C-like union REF for FFI compatibility. 🝖
为了与 FFI 兼容性,使用不安全的类 C 联合体 REF🝖
static X: T = T();Global variable BK EX REF with 'static lifetime, single memory location.
全局变量 BK EX REF 具有 'static 生命周期,单个内存位置。
const X: T = T();Defines constant, BK EX REF copied into a temporary when used.
定义常量, BK EX REF 在使用时复制到临时变量中。
let x: T;Allocate T bytes on stack1 bound as x. Assignable once, not mutable.
在栈 1 上分配 T 字节,绑定为 x 。可分配一次,不可变。
let mut x: T;Like let, but allow for mutability BK EX and mutable borrow.2
类似于 let ,但允许可变性 BK EX 和可变借用。 2
     x = y;Moves y to x, inval. y if T is not Copy, STD and copying y otherwise.
y 移动到 x ,如果 T 不是 Copy ,则无效 ySTD 并复制 y

1 Bound variables BK EX REF live on stack for synchronous code. In async {} they become part of async's state machine, may reside on heap.
1 绑定变量 BK EX REF 在同步代码中存储在堆栈上。在 async {} 中,它们成为异步状态机的一部分,可能驻留在堆上。

2 Technically mutable and immutable are misnomer. Immutable binding or shared reference may still contain Cell STD, giving interior mutability.
2 从技术上讲,可变和不可变是错误的术语。不可变绑定或共享引用仍可能包含 Cell STD ,从而具有内部可变性。

 

Creating and accessing data structures; and some more sigilic types.
创建和访问数据结构;以及一些更多的符号类型。

Example 示例Explanation 解释
S { x: y }Create struct S {} or use'ed enum E::S {} with field x set to y.
创建 struct S {}useenum E::S {} ,其中字段 x 设置为 y
S { x }Same, but use local variable x for field x.
相同,但对字段 x 使用本地变量 x
S { ..s }Fill remaining fields from s, esp. useful with Default::default(). STD
s 填充剩余字段,特别是与 Default::default() 一起使用。 STD
S { 0: x }Like S ​(x) below, but set field .0 with struct syntax.
像下面的 S (x) 一样,但使用结构语法设置字段 .0
S​ (x)Create struct S ​(T) or use'ed enum E::S​ () with field .0 set to x.
创建 struct S (T)use 'ed enum E::S () ,其中字段 .0 设置为 x
SIf S is unit struct S; or use'ed enum E::S create value of S.
如果 S 是单位 struct S;use 'ed enum E::S 创建价值 S
E::C { x: y }Create enum variant C. Other methods above also work.
创建枚举变体 C 。上面的其他方法也适用。
()Empty tuple, both literal and type, aka unit. STD
空元组,字面和类型都是单元。 STD
(x)Parenthesized expression.
括号表达式。
(x,)Single-element tuple expression. EX STD REF
单元素元组表达式。 EX STD REF
(S,)Single-element tuple type.
单元素元组类型。
[S]Array type of unspec. length, i.e., slice. EX STD REF Can't live on stack. *
未指定长度的数组类型,即切片。 EX STD REF 不能存在于堆栈上。 *
[S; n]Array type EX STD REF of fixed length n holding elements of type S.
固定长度为 n 的数组类型 EX STD REF ,其中包含类型为 S 的元素。
[x; n]Array instance REF (expression) with n copies of x.
数组实例 REF (表达式),包含 nx 的副本。
[x, y]Array instance with given elements x and y.
具有给定元素 xy 的数组实例。
x[0]Collection indexing, here w. usize. Impl. via Index, IndexMut.
集合索引,这里 w. usize . 通过 Index,IndexMut 实现。
     x[..]Same, via range (here full range), also x[a..b], x[a..=b], … c. below.
相同,通过范围(这里是完整范围),也 x[a..b]x[a..=b] ,… c. 如下。
a..bRight-exclusive range STD REF creation, e.g., 1..3 means 1, 2.
右独占范围 STD REF 创建,例如, 1..3 表示 1, 2
..bRight-exclusive range to STD without starting point.
右独占范围到 STD ,不包括起始点。
..=bInclusive range to STD without starting point.
包含范围到 STD ,不包括起始点。
a..=bInclusive range, STD 1..=3 means 1, 2, 3.
包含范围, STD1..=3 表示 1, 2, 3
a..Range from STD without ending point.
STD 开始的范围,没有结束点。
..Full range, STD usually means the whole collection.
全范围, STD 通常表示整个集合。
s.xNamed field access, REF might try to Deref if x not part of type S.
命名字段访问, REF 如果 x 不是类型 S 的一部分,可能会尝试解引用。
s.0Numbered field access, used for tuple types S ​(T).
编号字段访问,用于元组类型 S (T)

* For now,RFC pending completion of tracking issue.
目前, RFC 等待跟踪问题的完成。

References & Pointers 引用和指针url

Granting access to un-owned memory. Also see section on Generics & Constraints.
授予对未拥有的内存的访问。另请参阅有关泛型和约束的部分。

Example 示例Explanation 解释
&SShared reference BK STD NOM REF (type; space for holding any &s).
共享引用 BK STD NOM REF (类型;用于保存任何 &s 的空间)。
     &[S]Special slice reference that contains (address, count).
特殊的切片引用,包含 ( address , count )。
     &strSpecial string slice reference that contains (address, byte_length).
包含 ( address , byte_length ) 的特殊字符串切片引用。
     &mut SExclusive reference to allow mutability (also &mut [S], &mut dyn S, …).
允许可变性的独占引用(也包括 &mut [S]&mut dyn S ,...)。
     &dyn TSpecial trait object BK reference that contains (address, vtable).
特殊特性对象 BK 引用,包含 ( address , vtable )。
&sShared borrow BK EX STD (e.g., addr., len, vtable, … of this s, like 0x1234).
共享借用 BK EX STD (例如,此 s 的地址、长度、虚表等,如 0x1234 )。
     &mut sExclusive borrow that allows mutability. EX
允许可变性的独占借用。 EX
*const SImmutable raw pointer type BK STD REF w/o memory safety.
不可变的原始指针类型 BK STD REF ,没有内存安全。
     *mut SMutable raw pointer type w/o memory safety.
可变的原始指针类型,没有内存安全性。
     &raw const sCreate raw pointer w/o going through ref.; c. ptr:addr_of!() STD 🚧 🝖
创建原始指针,无需通过引用。c. ptr:addr_of!() STD 🚧 🝖
     &raw mut sSame, but mutable. 🚧 Needed for unaligned, packed fields. 🝖
相同,但可变。 🚧 用于不对齐的打包字段。 🝖
ref sBind by reference, EX makes binding reference type. 🗑️
通过引用绑定, EX 使绑定引用类型。 🗑️
     let ref r = s;Equivalent to let r = &s. 等同于 let r = &s
     let S { ref mut x } = s;Mut. ref binding (let x = &mut s.x), shorthand destructuring version.
Mut. ref 绑定( let x = &mut s.x ),简写解构 版本。
*rDereference BK STD NOM a reference r to access what it points to.
取消引用 BK STD NOM 引用 r 以访问其指向的内容。
     *r = s;If r is a mutable reference, move or copy s to target memory.
如果 r 是可变引用,则将 s 移动或复制到目标内存。
     s = *r;Make s a copy of whatever r references, if that is Copy.
使 s 成为 r 引用的副本,如果 Copy 的话。
     s = *r;Won't work 🛑 if *r is not Copy, as that would move and leave empty.
如果 *r 不是 Copy ,那么 🛑 将无法运行,因为这会移动并留下空白。
     s = *my_box;Special case🔗 for BoxSTD that can move out b'ed content not Copy.
特殊情况 🔗 对于 Box STD 可能移出 b'ed 内容而不是 Copy
'aA lifetime parameter, BK EX NOM REF duration of a flow in static analysis.
一个终身参数, BK EX NOM REF 静态分析流程的持续时间。
     &'a SOnly accepts address of some s; address existing 'a or longer.
只接受一些 s 的地址;地址存在 'a 或更长。
     &'a mut SSame, but allow address content to be changed.
相同,但允许更改地址内容。
     struct S<'a> {}Signals this S will contain address with lt. 'a. Creator of S decides 'a.
S 信号将包含地址与 lt。 'aS 的创建者决定 'a
     trait T<'a> {}Signals any S, which impl T for S, might contain address.
信号任何 S ,其中 impl T for S ,可能包含地址。
     fn f<'a>(t: &'a T)Signals this function handles some address. Caller decides 'a.
此函数处理某个地址的信号。调用者决定 'a
'staticSpecial lifetime lasting the entire program execution.
整个程序执行期间持续的特殊生命周期。

Functions & Behavior 功能和行为url

Define units of code and their abstractions.
定义代码单元及其抽象。

Example 示例Explanation 解释
trait T {}Define a trait; BK EX REF common behavior types can adhere to.
定义一个特质; BK EX REF 通用行为类型可以遵循。
trait T : R {}T is subtrait of supertrait BK EX REF R. Any S must impl R before it can impl T.
T 是超 trait BK EX REF R 的子 trait。任何 S 必须在能够 impl T 之前 impl R
impl S {}Implementation REF of functionality for a type S, e.g., methods.
对类型 S 的功能实现 REF ,例如方法。
impl T for S {}Implement trait T for type S; specifies how exactly S acts like T.
为类型 S 实现特质 T ;指定了 S 如何表现得像 T
impl !T for S {}Disable an automatically derived auto trait. NOM REF 🚧 🝖
禁用自动生成的自动 trait。 NOM REF 🚧 🝖
fn f() {}Definition of a function; BK EX REF or associated function if inside impl.
函数的定义; BK EX REF 或者如果在 impl 中则为相关函数。
     fn f() -> S {}Same, returning a value of type S.
相同,返回类型为 S 的值。
     fn f(&self) {}Define a method, BK EX REF e.g., within an impl S {}.
impl S {} 中定义一个方法, BK EX REF 例如。
struct S ​(T);More arcanely, also defines fn S(x: T) -> S constructor fn. RFC 🝖
更加神秘的是,也 定义 fn S(x: T) -> S 构造函数。 RFC 🝖
const fn f() {}Constant fn usable at compile time, e.g., const X: u32 = f(Y). REF '18
在编译时常量 fn 可用,例如, const X: u32 = f(Y)REF '18
     const { x }Used within a function, ensures { x } evaluated during compilation. ? 🚧
在函数内部使用,确保 { x } 在编译期间被评估。 ? 🚧
async fn f() {}Async REF '18 function transform, makes f return an impl Future. STD
异步 REF '18 函数转换, 使 f 返回一个 impl FutureSTD
     async fn f() -> S {}Same, but make f return an impl Future<Output=S>.
相同,但使 f 返回 impl Future<Output=S>
     async { x }Used within a function, make { x } an impl Future<Output=X>. REF
在函数内使用,使 { x } 成为 impl Future<Output=X>REF
     async move { x }Moves captured variables into future, c. move closure. REF
将捕获的变量移动到未来,c. 移动闭包。 REF
fn() -> SFunction references, 1 BK STD REF memory holding address of a callable.
函数引用, 1 BK STD REF 内存保存着可调用对象的地址。
Fn() -> SCallable Trait BK STD (also FnMut, FnOnce), impl. by closures, fn's …
可调用特质 BK STD (也 FnMutFnOnce ),由闭包、fn's 实现...
|| {} A closure BK EX REF that borrows its captures, REF (e.g., a local variable).
一个闭包 BK EX REF ,借用了它的捕获物, REF (例如,一个局部变量)。
     |x| {}Closure accepting one argument named x, body is block expression.
闭包接受一个名为 x 的参数,主体是块表达式。
     |x| x + xSame, without block expression; may only consist of single expression.
相同,没有块表达式;可能只包含单个表达式。
     move |x| x + y Move closure REF taking ownership; i.e., y transferred into closure.
将闭包 REF 拥有权;即 y 转移到闭包中。
     return || true Closures sometimes look like logical ORs (here: return a closure).
闭包有时看起来像逻辑或运算(这里:返回一个闭包)。
unsafeIf you enjoy debugging segfaults; unsafe code. BK EX NOM REF
如果您喜欢调试段错误;不安全的代码。 BK EX NOM REF
     unsafe fn f() {}Means "calling can cause UB, YOU must check requirements".
意味着“调用可能导致 UB, 您必须检查要求”。
     unsafe trait T {}Means "careless impl. of T can cause UB; implementor must check".
意味着“对 T 的粗心实现可能导致 UB;实现者必须检查”。
     unsafe { f(); }Guarantees to compiler "I have checked requirements, trust me".
保证编译器“我已经检查过要求,相信我”。
     unsafe impl T for S {}Guarantees S is well-behaved w.r.t T; people may use T on S safely.
保证 S 相对于 T 是良好的;人们可以安全地在 S 上使用 T

1 Most documentation calls them function pointers, but function references might be more appropriate🔗 as they can't be null and must point to valid target.
1 大多数文档将它们称为函数指针,但函数引用可能更合适 🔗 ,因为它们不能被 null ,必须指向有效的目标。

Control Flow 控制流url

Control execution within a function.
在函数内控制执行。

Example 示例Explanation 解释
while x {}Loop, REF run while expression x is true.
循环,当表达式 x 为真时运行 REF
loop {}Loop indefinitely REF until break. Can yield value with break x.
无限循环 REF 直到 break 。可以使用 break x 产生值。
for x in collection {}Syntactic sugar to loop over iterators. BK STD REF
用于遍历迭代器的语法糖。 BK STD REF
     ↪  collection.into_iter() Effectively converts any IntoIterator STD type into proper iterator first.
有效地将任何 IntoIterator STD 类型转换为适当的迭代器。
     ↪  iterator.next() On proper Iterator STD then x = next() until exhausted (first None).
在适当的 Iterator STD 然后 x = next() 直到耗尽(第一个 None )。
if x {} else {}Conditional branch REF if expression is true.
如果表达式为真,则条件分支 REF
'label: {}Block label, RFC can be used with break to exit out of this block. 1.65+
块标签, RFC 可与 break 一起使用以退出此块。 1.65+
'label: loop {}Similar loop label, EX REF useful for flow control in nested loops.
类似的循环标签, EX REF 在嵌套循环中用于流程控制。
breakBreak expression REF to exit a labelled block or loop.
将表达式 REF 分解为退出标记块或循环。
     break 'label xBreak out of block or loop named 'label and make x its value.
打破名为 'label 的块或循环,并将 x 作为其值。
     break 'labelSame, but don't produce any value.
相同,但不生成任何值。
     break xMake x value of the innermost loop (only in actual loop).
使最内层循环的 x 值(仅在实际 loop 中)。
continue Continue expression REF to the next loop iteration of this loop.
将表达式 REF 继续到此循环的下一个迭代。
continue 'labelSame but instead of this loop, enclosing loop marked with 'label.
相同,但是不是这个循环,而是用'label 标记的封闭循环。
x?If x is Err or None, return and propagate. BK EX STD REF
如果 x 是 Err 或 None,则返回并传播。 BK EX STD REF
x.awaitSyntactic sugar to get future, poll, yield. REF '18 Only inside async.
获取 future、poll、yield 的语法糖。 REF '18 仅在 async 内部。
     ↪  x.into_future() Effectively converts any IntoFuture STD type into proper future first.
有效地将任何 IntoFuture STD 类型转换为适当的未来第一。
     ↪  future.poll() On proper Future STD then poll() and yield flow if Poll::Pending. STD
在适当的 Future STD 然后 poll() 并且如果 Poll::Pending 则产生流量。 STD
return xEarly return REF from fn. More idiomatic is to end with expression.
从 fn 中提前返回 REF 。更惯用的方式是以表达式结束。
     { return }Inside normal {}-blocks return exits surrounding function.
在普通 {} 块内 return 退出周围函数。
     || { return }Within closures return exits that c. only, i.e., closure is s. fn.
在闭包中, return 仅限于退出 c.,即闭包是 s. fn.
     async { return }Inside async a return only REF 🛑 exits that {}, i.e., async {} is s. fn.
async 中,只有 REF 🛑 存在,即 async {} 是 s. fn。
f()Invoke callable f (e.g., a function, closure, function pointer, Fn, …).
调用可调用项 f (例如,函数、闭包、函数指针, Fn ,...)。
x.f()Call member fn, requires f takes self, &self, … as first argument.
调用成员函数,需要 f 作为第一个参数。
     X::f(x)Same as x.f(). Unless impl Copy for X {}, f can only be called once.
x.f() 相同。除非 impl Copy for X {} ,否则 f 只能被调用一次。
     X::f(&x)Same as x.f(). x.f()
     X::f(&mut x)Same as x.f(). x.f()
     S::f(&x)Same as x.f() if X derefs to S, i.e., x.f() finds methods of S.
如果 X 解引用到 S ,则与 x.f() 相同,即 x.f() 找到 S 的方法。
     T::f(&x)Same as x.f() if X impl T, i.e., x.f() finds methods of T if in scope.
如果 X impl T ,则与 x.f() 相同,即在范围内找到 T 方法的 x.f()
X::f()Call associated function, e.g., X::new().
调用关联函数,例如, X::new()
     <X as T>::f()Call trait method T::f() implemented for X.
调用为 X 实现的特质方法 T::f()

Organizing Code 组织代码url

Segment projects into smaller units and minimize dependencies.
将项目分割为较小单元并最小化依赖关系。

Example 示例Explanation 解释
mod m {}Define a module, BK EX REF get definition from inside {}.
定义一个模块, BK EX REF 从内部获取定义 {}
mod m;Define a module, get definition from m.rs or m/mod.rs.
定义一个模块,从 m.rsm/mod.rs 获取定义。
a::bNamespace path EX REF to element b within a (mod, enum, …).
a 中的元素 b 的命名空间路径 EX REF ( mod , enum , …)。
     ::bSearch b in crate root '15 REF or ext. prelude; '18 REF global path. REF 🗑️
在箱根 '15 REF 或 ext. 前奏中搜索 b'18 REF 全局路径。 REF 🗑️
     crate::bSearch b in crate root. '18
在 crate 根目录中搜索 b'18
     self::bSearch b in current module.
在当前模块中搜索 b
     super::bSearch b in parent module.
在父模块中搜索 b
use a::b;Use EX REF b directly in this scope without requiring a anymore.
在此范围内直接使用 EX REF b ,而无需再需要 a
use a::{b, c};Same, but bring b and c into scope.
相同,但将 bc 引入范围。
use a::b as x;Bring b into scope but name x, like use std::error::Error as E.
b 引入范围,但命名为 x ,如 use std::error::Error as E
use a::b as _;Bring b anon. into scope, useful for traits with conflicting names.
b 匿名引入作用域,适用于具有冲突名称的特性。
use a::*;Bring everything from a in, only recomm. if a is some prelude. STD 🔗
a 中的所有内容带入,仅在 a 是某种序言时推荐。 STD 🔗
pub use a::b;Bring a::b into scope and reexport from here.
a::b 引入范围并从此重新导出。
pub T"Public if parent path is public" visibility BK REF for T.
"如果父路径是公共的,则可见性为 BK REF T 。"
     pub(crate) TVisible at most1 in current crate.
当前 crate 中最多可见 1
     pub(super) TVisible at most1 in parent.
在父级中最多可见 1
     pub(self) TVisible at most1 in current module (default, same as no pub).
当前模块中最多可见 1 (默认值,与无 pub 相同)。
     pub(in a::b) TVisible at most1 in ancestor a::b.
在祖先 a::b 中最多可见 1
extern crate a;Declare dependency on external crate; BK REF 🗑️ just use a::b in '18.
在外部创建依赖关系; BK REF 🗑️ 只需在 '18use a::b
extern "C" {}Declare external dependencies and ABI (e.g., "C") from FFI. BK EX NOM REF
声明来自 FFI 的外部依赖项和 ABI(例如, "C" )。 BK EX NOM REF
extern "C" fn f() {}Define function to be exported with ABI (e.g., "C") to FFI.
定义要导出到 FFI 的具有 ABI(例如, "C" )的函数。

1 Items in child modules always have access to any item, regardless if pub or not.
子模块中的 1 项始终可以访问任何项,无论 pub 与否。

Type Aliases and Casts 类型别名和转换url

Short-hand names of types, and methods to convert one type to another.
类型的简称,以及将一种类型转换为另一种类型的方法。

Example 示例Explanation 解释
type T = S;Create a type alias, BK REF i.e., another name for S.
创建一个类型别名, BK REF ,即 S 的另一个名称。
SelfType alias for implementing type, REF e.g., fn new() -> Self.
用于实现类型的类型别名, REF 例如, fn new() -> Self
selfMethod subject BK REF in fn f(self) {}, e.g., akin to fn f(self: Self) {}.
方法主题 BK REFfn f(self) {} ,例如,类似于 fn f(self: Self) {}
     &selfSame, but refers to self as borrowed, would equal f(self: &Self)
相同,但将自身称为借用,将等于 f(self: &Self)
     &mut selfSame, but mutably borrowed, would equal f(self: &mut Self)
相同,但是可变借用,将等于 f(self: &mut Self)
     self: Box<Self>Arbitrary self type, add methods to smart ptrs (my_box.f_of_self()).
任意自身类型,向智能指针添加方法( my_box.f_of_self() )。
<S as T>Disambiguate BK REF type S as trait T, e.g., <S as T>::f().
BK REF 类型 S 作为 trait T 进行消歧义,例如, <S as T>::f()
a::b as cIn use of symbol, import S as R, e.g., use a::S as R.
use 中,导入 S 作为 R ,例如, use a::S as R
x as u32Primitive cast, EX REF may truncate and be a bit surprising. 1 NOM
原始转换, EX REF 可能会截断并且有点令人惊讶。 1 NOM

1 See Type Conversions below for all the ways to convert between types.
1 请参阅下面的类型转换,了解所有类型之间的转换方式。

Macros & Attributes 宏和属性url

Code generation constructs expanded before the actual compilation happens.
在实际编译发生之前,代码生成结构被展开。

Example 示例Explanation 解释
m!()Macro BK STD REF invocation, also m!{}, m![] (depending on macro).
BK STD REF 调用,也 m!{}m![] (取决于宏)。
#[attr]Outer attribute, EX REF annotating the following item.
外部属性, EX REF 注释以下项目。
#![attr]Inner attribute, annotating the upper, surrounding item.
内部属性,注释上方、周围项目。
 
Inside Macros 1 宏内 1 Explanation 解释
$x:tyMacro capture, the :ty fragment specifier REF ,2 declares what $x may be.
宏捕获, :ty 片段说明符 REF ,2 声明了什么可能是 $x
$xMacro substitution, e.g., use the captured $x:ty from above.
宏替换,例如,使用上面捕获的 $x:ty
$(x),*Macro repetition REF zero or more times.
宏重复 REF 零次或多次。
     $(x),+Same, but one or more times.
相同,但一次或多次。
     $(x)?Same, but zero or one time (separator doesn't apply).
相同,但零次或一次(分隔符不适用)。
     $(x)<<+In fact separators other than , are also accepted. Here: <<.
实际上,除了 , 之外,也可以接受其他分隔符。这里是: <<

1 Applies to 'macros by example'. REF
1 适用于“宏示例”。 REF

2 See Tooling Directives below for all fragment specifiers.
2 请参阅下面的工具指令,了解所有片段标识符。

Pattern Matching 模式匹配url

Constructs found in match or let expressions, or function parameters.
matchlet 表达式中找到的构造,或函数参数。

Example 示例Explanation 解释
match m {}Initiate pattern matching, BK EX REF then use match arms, c. next table.
启动模式匹配, BK EX REF 然后使用匹配分支,c. 下一个表。
let S(x) = get();Notably, let also destructures EX similar to the table below.
值得注意的是, let 还会像下表一样解构 EX
     let S { x } = s;Only x will be bound to value s.x.
只有 x 将绑定到值 s.x
     let (_, b, _) = abc;Only b will be bound to value abc.1.
只有 b 将绑定到值 abc.1
     let (a, ..) = abc;Ignoring 'the rest' also works.
忽略“其余”的操作也是有效的。
     let (.., a, b) = (1, 2);Specific bindings take precedence over 'the rest', here a is 1, b is 2.
特定绑定优先于“其余部分”,这里 a1b2
     let s @ S { x } = get();Bind s to S while x is bnd. to s.x, pattern binding, BK EX REF c. below 🝖
s 绑定到 S ,同时 x 绑定到 s.x ,模式绑定, BK EX REF 如下 🝖
     let w @ t @ f = get();Stores 3 copies of get() result in each w, t, f. 🝖
在每个 wtf 中存储 get() 结果的 3 个副本。 🝖
     let (|x| x) = get();Pathological or-pattern, not closure.🛑 Same as let x = get(); 🝖
病态的或模式, 不是闭包。 🛑let x = get(); 🝖 相同
let Some(x) = get();Won't work 🛑 if p. can be refuted, REF use let else or if let instead.
如果 p 可以被反驳,则 🛑 不起作用, REF 请使用 let elseif let
let Some(x) = get() else {};Try to assign RFC if not else {} w. must break, return, panic!, … 1.65+ 🔥
尝试分配 RFC ,如果不是 else {} ,则必须 breakreturnpanic! ,… 1.65+ 🔥
if let Some(x) = get() {}Branch if pattern can be assigned (e.g., enum variant), syntactic sugar. *
如果可以分配模式(例如, enum 变体),则分支,语法糖。 *
while let Some(x) = get() {}Equiv.; here keep calling get(), run {} as long as p. can be assigned.
等效;在这里不断调用 get() ,只要可以分配 p.就运行 {}
fn f(S { x }: S)Function param. also work like let, here x bound to s.x of f(s). 🝖
函数参数也像 let 一样工作,这里 x 绑定到 f(s)s.x🝖

* Desugars to match get() { Some(x) => {}, _ => () }.
展开为 match get() { Some(x) => {}, _ => () }

 

Pattern matching arms in match expressions. Left side of these arms can also be found in let expressions.
match 表达式中的模式匹配分支。这些分支的左侧也可以在 let 表达式中找到。

Within Match Arm 在 Match Arm 内Explanation 解释
E::A => {}Match enum variant A, c. pattern matching. BK EX REF
匹配枚举变体 A ,c。模式匹配。 BK EX REF
E::B ( .. ) => {}Match enum tuple variant B, ignoring any index.
匹配枚举元组变体 B ,忽略任何索引。
E::C { .. } => {}Match enum struct variant C, ignoring any field.
匹配枚举结构变体 C ,忽略任何字段。
S { x: 0, y: 1 } => {}Match s. with specific values (only s with s.x of 0 and s.y of 1).
匹配具有特定值的 s.(仅 ss.x0s.y1 )。
S { x: a, y: b } => {}Match s. with any 🛑 values and bind s.x to a and s.y to b.
将 s.与任何 🛑 值匹配,并将 s.x 绑定到 a ,将 s.y 绑定到 b
     S { x, y } => {}Same, but shorthand with s.x and s.y bound as x and y respectively.
相同,但使用 s.xs.y 绑定为 xy
S { .. } => {}Match struct with any values.
与任何值匹配的结构。
D => {}Match enum variant E::D if D in use.
匹配枚举变体 E::D 如果 Duse 中。
D => {}Match anything, bind D; possibly false friend 🛑 of E::D if D not in use.
匹配任何内容,绑定 D ;如果 D 不在 use 中,则可能是错误的朋友 🛑E::D
_ => {}Proper wildcard that matches anything / "all the rest".
适当的通配符,匹配任何内容/“所有剩余内容”。
0 | 1 => {}Pattern alternatives, or-patterns. RFC
模式替代方案,或模式。 RFC
     E::A | E::Z => {}Same, but on enum variants.
相同,但是在枚举变体上。
     E::C {x} | E::D {x} => {}Same, but bind x if all variants have it.
相同,但如果所有变体都有它,则绑定 x
     Some(A | B) => {}Same, can also match alternatives deeply nested.
相同,也可以深度匹配嵌套的替代项。
     |x| x => {}Pathological or-pattern,🛑 leading | ignored, is just x | x, thus x. 🝖
病态的或模式, 🛑 领先 | 被忽略,只是 x | x ,因此 x🝖
(a, 0) => {}Match tuple with any value for a and 0 for second.
匹配元组,对于第二个位置, a0 可以是任意值。
[a, 0] => {}Slice pattern, REF 🔗 match array with any value for a and 0 for second.
切片模式, REF 🔗 匹配数组中任何值的 a0 为第二。
     [1, ..] => {}Match array starting with 1, any value for rest; subslice pattern. REF RFC
匹配以 1 开头的数组,其余部分可以是任意值;子切片模式。 REF RFC
     [1, .., 5] => {}Match array starting with 1, ending with 5.
匹配以 1 开头,以 5 结尾的数组。
     [1, x @ .., 5] => {}Same, but also bind x to slice representing middle (c. pattern binding).
相同,但还将 x 绑定到表示中间的切片(c.模式绑定)。
     [a, x @ .., b] => {}Same, but match any first, last, bound as a, b respectively.
相同,但匹配任何第一个、最后一个、边界分别为 ab
1 .. 3 => {}Range pattern, BK REF here matches 1 and 2; partially unstable. 🚧
范围模式, BK REF 这里匹配 12 ;部分不稳定。 🚧
     1 ..= 3 => {}Inclusive range pattern, matches 1, 2 and 3.
包含范围模式,匹配 123
     1 .. => {}Open range pattern, matches 1 and any larger number.
打开范围模式,匹配 1 和任何更大的数字。
x @ 1..=5 => {}Bind matched to x; pattern binding, BK EX REF here x would be 15.
绑定匹配到 x ;模式绑定, BK EX REF 这里 x 将会是 15
     Err(x @ Error {..}) => {}Also works nested, here x binds to Error, esp. useful with if below.
也可以嵌套使用,在这里 x 绑定到 Error ,特别是与下面的 if 结合使用非常有用。
S { x } if x > 10 => {}Pattern match guards, BK EX REF condition must be true as well to match.
模式匹配保护, BK EX REF 条件也必须为真才能匹配。

Generics & Constraints 泛型和约束url

Generics combine with type constructors, traits and functions to give your users more flexibility.
泛型与类型构造函数、特质和函数结合在一起,为您的用户提供更多的灵活性。

Example 示例Explanation 解释
struct S<T> …A generic BK EX type with a type parameter (T is placeholder here).
一个带有类型参数( T 在这里是占位符)的通用 BK EX 类型。
S<T> where T: RTrait bound, BK EX REF limits allowed T, guarantees T has trait R.
Trait bound, BK EX REF 限制允许 T ,保证 T 具有 trait R
     where T: R, P: SIndependent trait bounds, here one for T and one for (not shown) P.
独立特质边界,这里一个是 T ,另一个是(未显示) P
     where T: R, SCompile error, 🛑 you probably want compound bound R + S below.
编译错误, 🛑 您可能想要复合边界 R + S 在下面。
     where T: R + SCompound trait bound, BK EX T must fulfill R and S.
复合特质约束, BK EX T 必须满足 RS
     where T: R + 'aSame, but w. lifetime. T must fulfill R, if T has lt., must outlive 'a.
相同,但带有生命周期。 T 必须满足 R ,如果 T 有 lt.,必须比 'a 存活更久。
     where T: ?SizedOpt out of a pre-defined trait bound, here Sized. ?
Opt out of a pre-defined trait bound, here Sized . ? .
     where T: 'aType lifetime bound; EX if T has references, they must outlive 'a.
类型生命周期约束; 如果 T 具有引用,则它们必须比 'a 存在更长的时间。
     where T: 'staticSame; does not mean value t will 🛑 live 'static, only that it could.
相同;并不意味着值 t🛑'static ,只是可能。
     where 'b: 'aLifetime 'b must live at least as long as (i.e., outlive) 'a bound.
生命周期 'b 必须至少与 'a 绑定的生命周期一样长。
     where u8: R<T>Can also make conditional statements involving other types. 🝖
还可以创建涉及其他类型的条件语句。 🝖
S<T: R>Short hand bound, almost same as above, shorter to write.
简写绑定,几乎与上面相同,写起来更短。
S<const N: usize>Generic const bound; REF user of type S can provide constant value N.
通用 const 约束; REF 类型的用户可以提供常量值 N
     S<10>Where used, const bounds can be provided as primitive values.
在使用时,const bounds 可以作为原始值提供。
     S<{5+5}>Expressions must be put in curly brackets.
表达式必须放在花括号中。
S<T = R>Default parameters; BK makes S a bit easier to use, but keeps flexible.
默认参数; BK 使 S 更易于使用,但保持灵活性。
     S<const N: u8 = 0>Default parameter for constants; e.g., in f(x: S) {} param N is 0.
常量的默认参数;例如,在 f(x: S) {} 参数 N0
     S<T = u8>Default parameter for types, e.g., in f(x: S) {} param T is u8.
类型的默认参数,例如,在 f(x: S) {} 参数 Tu8
S<'_>Inferred anonymous lt.; asks compiler to 'figure it out' if obvious.
推断匿名 lt。;如果显而易见,要求编译器“弄清楚”。
S<_>Inferred anonymous type, e.g., as let x: Vec<_> = iter.collect()
推断的匿名类型,例如,如 let x: Vec<_> = iter.collect()
S::<T>Turbofish STD call site type disambiguation, e.g., f::<u32>().
Turbofish STD 调用站点类型消歧义,例如, f::<u32>()
trait T<X> {}A trait generic over X. Can have multiple impl T for S (one per X).
一个泛型特征,覆盖 X 。可以有多个 impl T for S (每个 X 一个)。
trait T { type X; }Defines associated type BK REF RFC X. Only one impl T for S possible.
定义关联类型 BK REF RFC X 。仅允许一个 impl T for S
trait T { type X<G>; }Defines generic associated type (GAT), RFC X can be generic Vec<>.
定义通用关联类型(GAT), RFC X 可以是通用 Vec<>
trait T { type X<'a>; }Defines a GAT generic over a lifetime.
定义了一个在生命周期上通用的 GAT。
     type X = R;Set associated type within impl T for S { type X = R; }.
impl T for S { type X = R; } 中设置关联类型。
     type X<G> = R<G>;Same for GAT, e.g., impl T for S { type X<G> = Vec<G>; }.
对于 GAT,例如, impl T for S { type X<G> = Vec<G>; }
impl<T> S<T> {}Impl. fn's for any T in S<T> generically, REF here T ty. parameter.
S<T> 中通用地实现 Tfn ,在这里 T 类型参数。
impl S<T> {}Impl. fn's for exactly S<T> inherently, REF here T specific type, e.g., u8.
实现 fn 的确切 S<T> 本质上, REF 这里 T 具体类型,例如, u8
fn f() -> impl TExistential types, BK returns an unknown-to-caller S that impl T.
存在类型, BK 返回一个对调用者未知的 S ,该 impl T
fn f(x: &impl T)Trait bound via "impl traits", BK similar to fn f<S: T>(x: &S) below.
通过“impl traits”进行特质绑定, BK 类似于下面的 fn f<S: T>(x: &S)
fn f(x: &dyn T)Invoke f via dynamic dispatch, BK REF f will not be instantiated for x.
通过动态调度调用 fBK REF f 将不会为 x 实例化。
fn f<X: T>(x: X)Fn. generic over X, f will be instantiated ('monomorphized') per X.
Fn. 通用于 Xf 将根据 X 实例化('单态化')。
fn f() where Self: R;In trait T {}, make f accessible only on types known to also impl R.
trait T {} 中,仅在已知也 impl R 的类型上使 f 可访问。
     fn f() where Self: Sized;Using Sized can opt f out of trait object vtable, enabling dyn T.
使用 Sized 可以选择 f 退出特性对象 vtable,从而启用 dyn T
     fn f() where Self: R {}Other R useful w. dflt. fn. (non dflt. would need be impl'ed anyway).
其他 R 有用的 w. dflt. fn.(非 dflt. 无论如何都需要被实现)。

Higher-Ranked Items 🝖
更高排名的项目 🝖
url

Actual types and traits, abstract over something, usually lifetimes.
实际类型和特质,通常涵盖某些内容,通常是生命周期。

Example 示例Explanation 解释
for<'a>Marker for higher-ranked bounds. NOM REF 🝖
更高级别边界的标记。 NOM REF 🝖
     trait T: for<'a> R<'a> {}Any S that impl T would also have to fulfill R for any lifetime.
任何 S 也必须满足任何生命周期的 R
fn(&'a u8)Function pointer type holding fn callable with specific lifetime 'a.
具有特定生命周期的可调用 fn 的函数指针类型 'a
for<'a> fn(&'a u8)Higher-ranked type1 🔗 holding fn call. with any lt.; subtype of above.
更高级别的类型 1 🔗 持有 fn 调用。具有任何 lt。; 子类型 在上述之上。
     fn(&'_ u8)Same; automatically expanded to type for<'a> fn(&'a u8).
相同;自动扩展为类型 for<'a> fn(&'a u8)
     fn(&u8)Same; automatically expanded to type for<'a> fn(&'a u8).
相同;自动扩展为类型 for<'a> fn(&'a u8)
dyn for<'a> Fn(&'a u8)Higher-ranked (trait-object) type, works like fn above.
更高排名的(特质对象)类型,类似于上面的 fn
     dyn Fn(&'_ u8)Same; automatically expanded to type dyn for<'a> Fn(&'a u8).
相同;自动扩展为类型 dyn for<'a> Fn(&'a u8)
     dyn Fn(&u8)Same; automatically expanded to type dyn for<'a> Fn(&'a u8).
相同;自动扩展为类型 dyn for<'a> Fn(&'a u8)

1 Yes, the for<> is part of the type, which is why you write impl T for for<'a> fn(&'a u8) below.
1 是的, for<> 是类型的一部分,这就是为什么你在下面写 impl T for for<'a> fn(&'a u8)

 
Implementing Traits 实现特性Explanation 解释
impl<'a> T for fn(&'a u8) {}For fn. pointer, where call accepts specific lt. 'a, impl trait T.
对于 fn. 指针,调用接受特定的 lt. 'a ,实现 trait T
impl T for for<'a> fn(&'a u8) {}For fn. pointer, where call accepts any lt., impl trait T.
对于 fn. 指针,其中调用接受任何 lt.,impl trait T
     impl T for fn(&u8) {}Same, short version. 相同,简短版本。

Strings & Chars 字符串和字符url

Rust has several ways to create textual values.
Rust 有几种创建文本值的方式。

Example 示例Explanation 解释
"..."String literal, REF, 1 a UTF-8 &'static str, STD supporting these escapes:
字符串字面量, REF , 1 一个 UTF-8 &'static strSTD 支持这些转义:
     "\n\r\t\0\\"Common escapes REF, e.g., "\n" becomes new line.
常见的转义字符 REF ,例如, "\n" 变成换行。
     "\x36"ASCII e. REF up to 7f, e.g., "\x36" would become 6.
ASCII e. REF7f ,例如, "\x36" 将变为 6
     "\u{7fff}"Unicode e. REF up to 6 digits, e.g., "\u{7fff}" becomes 翿.
Unicode e。 REF 最多 6 位数字,例如, "\u{7fff}" 变为 翿
r"..."Raw string literal. REF, 1UTF-8, but won't interpret any escape above.
原始字符串字面量。 REF , 1 UTF-8,但不会解释任何以上的转义。
r#"..."#Raw string literal, UTF-8, but can also contain ". Number of # can vary.
原始字符串字面量,UTF-8,但也可以包含 "# 的数量可以变化。
c"..."C string literal, REF a NUL-terminated &'static CStr, STD for FFI. 1.77+
C 字符串字面量, REF 以 NUL 结尾的 &'static CStrSTD 用于 FFI。 1.77+
cr"...", cr#"..."#Raw C string literal, combination analog to above.
原始 C 字符串字面值,类似于上面的组合。
b"..."Byte string literal; REF, 1 constructs ASCII-only &'static [u8; N].
字节字符串文字; REF , 1 构造 ASCII-only &'static [u8; N]
br"...", br#"..."#Raw byte string literal, combination analog to above.
原始字节字符串文字,类似于上面的组合。
b'x'ASCII byte literal, REF a single u8 byte.
ASCII 字节文字, REF 一个单个 u8 字节。
'🦀'Character literal, REF fixed 4 byte unicode 'char'. STD
字符字面量, REF 固定 4 字节 Unicode 'char'。 STD

1 Supports multiple lines out of the box. Just keep in mind Debug (e.g., dbg!(x) and println!("{x:?}")) might render them as \n, while Display (e.g., println!("{x}")) renders them proper.
1 支持多行文本。只需记住 Debug (例如, dbg!(x)println!("{x:?}") )可能会将它们呈现为 \n ,而 Display (例如, println!("{x}") )会正确呈现它们。

Documentation 文档url

Debuggers hate him. Avoid bugs with this one weird trick.
调试器讨厌他。用这个奇怪的技巧避免错误。

Example 示例Explanation 解释
///Outer line doc comment,1 BK EX REF use these on ty., traits, fn's, …
外部行文档注释, 1 BK EX REF 在 ty.、traits、fn's 上使用这些…
//!Inner line doc comment, mostly used at top of file.
内部行文档注释,主要用于文件顶部。
//Line comment, use these to document code flow or internals.
行注释,用于记录代码流程或内部细节。
/* … */Block comment. 2 🗑️
块注释。 2 🗑️
/** … */Outer block doc comment. 2 🗑️
外部块文档注释。 2 🗑️
/*! … */Inner block doc comment. 2 🗑️
内部块文档注释。 2 🗑️

1 Tooling Directives outline what you can do inside doc comments.
1 工具指令概述了您可以在文档注释中执行的操作。

2 Generally discouraged due to bad UX. If possible use equivalent line comment instead with IDE support.
2 通常不建议使用,因为用户体验不佳。如果可能的话,最好使用等效的行注释,并获得 IDE 支持。

Miscellaneous 杂项url

These sigils did not fit any other category but are good to know nonetheless.
这些符印不属于任何其他类别,但了解它们仍然是有益的。

Example 示例Explanation 解释
!Always empty never type. BK EX STD REF
始终为空,永不输入。 BK EX STD REF
     fn f() -> ! {}Function that never ret.; compat. with any ty. e.g., let x: u8 = f();
永不返回的函数;与任何类型兼容,例如, let x: u8 = f();
     fn f() -> Result<(), !> {}Function that must return Result but signals it can never Err. 🚧
必须返回 Result 但表示永远不会 Err 的函数。 🚧
     fn f(x: !) {}Function that exists, but can never be called. Not very useful. 🝖 🚧
存在但永远不会被调用的函数。并不是很有用。 🝖 🚧
_Unnamed wildcard REF variable binding, e.g., |x, _| {}.
未命名通配符 REF 变量绑定,例如, |x, _| {}
     let _ = x;Unnamed assign. is no-op, does not 🛑 move out x or preserve scope!
未命名的赋值操作是无操作的,不会 🛑 移出 x 或保留作用域!
     _ = x;You can assign anything to _ without let, i.e., _ = ignore_rval(); 🔥
您可以将任何内容分配给 _ ,而无需 let ,即 _ = ignore_rval(); 🔥
_xVariable binding that won't emit unused variable warnings.
不会发出未使用变量警告的变量绑定。
1_234_567Numeric separator for visual clarity.
数字分隔符以增强可视清晰度。
1_u8Type specifier for numeric literals EX REF (also i8, u16, …).
数字字面量的类型说明符 EX REF (也可以是 i8u16 ,...)。
0xBEEF, 0o777, 0b1001Hexadecimal (0x), octal (0o) and binary (0b) integer literals.
十六进制( 0x ),八进制( 0o )和二进制( 0b )整数字面量。
r#fooA raw identifier BK EX for edition compatibility. 🝖
用于版本兼容性的原始标识符 BK EX🝖
x;Statement REF terminator, c. expressions EX REF
语句 REF 终止符,c.表达式 EX REF

Common Operators 常见运算符url

Rust supports most operators you would expect (+, *, %, =, ==, …), including overloading. STD Since they behave no differently in Rust we do not list them here.
Rust 支持大多数您期望的运算符( +*%=== ,…),包括重载。 STD 由于它们在 Rust 中的行为没有任何不同,我们在这里不列出它们。


Behind the Scenes 幕后花絮url

Arcane knowledge that may do terrible things to your mind, highly recommended.
神秘的知识可能会对你的思维造成可怕的影响,强烈推荐。

The Abstract Machine 抽象机器url

Like C and C++, Rust is based on an abstract machine.
CC++ 一样,Rust 基于一个抽象机器。

Rust CPU
🛑 Misleading.  🛑 误导性。
Rust Abstract Machine 抽象机器 CPU
Correct. 正确。
 

With rare exceptions you are never 'allowed to reason' about the actual CPU. You write code for an abstracted CPU. Rust then (sort of) understands what you want, and translates that into actual RISC-V / x86 / … machine code.
除非极少数情况,否则您永远不会“允许推理”实际的 CPU。您为一个抽象的 CPU 编写代码。然后 Rust(在某种程度上)理解您的意图,并将其转换为实际的 RISC-V / x86 / ... 机器码。

 

This abstract machine 这个抽象机器

  • is not a runtime, and does not have any runtime overhead, but is a computing model abstraction,
    不是运行时,并且没有任何运行时开销,而是一个计算模型抽象
  • contains concepts such as memory regions (stack, …), execution semantics, …
    包含诸如内存区域(堆栈,...),执行语义等概念
  • knows and sees things your CPU might not care about,
    了解并观察您的 CPU 可能不关心的事物,
  • is de-facto a contract between you and the compiler,
    这实际上是您和编译器之间的合同
  • and exploits all of the above for optimizations.
    并利用上述所有内容进行优化。

On the left things people may incorrectly assume they should get away with if Rust targeted CPU directly. On the right things you'd interfere with if in reality if you violate the AM contract.

 
Without AMWith AM
0xffff_ffff would make a valid char. 🛑AM may exploit 'invalid' bit patterns to pack unrelated data.
0xff and 0xff are same pointer. 🛑AM pointers can have 'domain' attached for optimization.
Any r/w on pointer 0xff always fine. 🛑AM may issue cache-friendly ops since 'no read possible'.
Reading un-init just gives random value. 🛑AM 'knows' read impossible, may remove all related code.
Data race just gives random value. 🛑AM may split R/W, produce impossible value, see above.
Null ref. is just 0x0 in some register. 🛑Holding 0x0 in reference summons Cthulhu.
 

This table is only to outline what the AM does. Unlike C or C++, Rust never lets you do the wrong thing unless you force it with unsafe.

Language Sugar 语言糖url

If something works that "shouldn't work now that you think about it", it might be due to one of these.
如果某些东西能够正常工作,而你事后想起来觉得“不应该能够工作”,那可能是由于以下原因之一。

Name 名称Description 描述
Coercions NOM 强制转换 NOM Weakens types to match signature, e.g., &mut T to &T; c. type conv.
弱化类型以匹配签名,例如, &mut T&T ;c. 类型转换
Deref NOM 🔗 解引用 NOM 🔗 Derefs x: T until *x, **x, … compatible with some target S.
直到 *x**x ,... 与某些目标 S 兼容,解引用 x: T
Prelude STD 序曲 STD Automatic import of basic items, e.g., Option, drop(), …
基本项目的自动导入,例如, Optiondrop() ,...
Reborrow 🔗 重新借用 🔗 Since x: &mut T can't be copied; moves new &mut *x instead.
由于 x: &mut T 无法复制;移动新的 &mut *x
Lifetime Elision BK NOM REF
生命周期省略 BK NOM REF
Allows you to write f(x: &T), instead of f<'a>(x: &'a T), for brevity.
允许您写 f(x: &T) ,而不是 f<'a>(x: &'a T) ,以简洁为主。
Lifetime Extensions 🔗 REF
寿命扩展 🔗 REF
In let x = &tmp().f and similar hold on to temporary past line.
let x = &tmp().f 和类似的保持对临时过去行的控制。
Method Resolution REF 方法解析 REF Derefs or borrow x until x.f() works.
解引用或借用 x 直到 x.f() 可用。
Match Ergonomics RFC 匹配人体工程学 RFC Repeatedly deref. scrutinee and adds ref and ref mut to bindings.
重复取消引用。检查并将 refref mut 添加到绑定。
Rvalue Static Promotion RFC 🝖
Rvalue 静态提升 RFC 🝖
Makes refs. to constants 'static, e.g., &42, &None, &mut [].
对常量 'static 进行引用,例如 &42&None&mut []
Dual Definitions RFC 🝖
双重定义 RFC 🝖
Defining one (e.g., struct S(u8)) implicitly def. another (e.g., fn S).
定义一个(例如, struct S(u8) )隐式定义另一个(例如, fn S )。
Drop Hidden Flow REF 🝖
隐藏流程已删除 REF 🝖
At end of blocks { ... } or _ assignment, may call T::drop(). STD
在块的末尾 { ... }_ 赋值时,可能调用 T::drop() . STD
Drop Not Callable STD 🝖
不可调用的 Drop STD 🝖
Compiler forbids explicit T::drop() call, must use mem::drop(). STD
编译器禁止显式调用 T::drop() ,必须使用 mem::drop()STD
 

Opinion 💬 — These features make your life easier using Rust, but stand in the way of learning it. If you want to develop a genuine understanding, spend some extra time exploring them.
意见 💬 — 这些功能使您在使用 Rust 时更加轻松,但会妨碍学习。如果您想真正理解,花一些额外时间来探索它们。

Memory & Lifetimes 内存和生命周期url

An illustrated guide to moves, references and lifetimes.
一个关于移动、引用和生命周期的图解指南。

Application Memory S(1) Application Memory 应用程序内存
  • Application memory is just array of bytes on low level.
  • Operating environment usually segments that, amongst others, into:
    • stack (small, low-overhead memory,1 most variables go here),
    • heap (large, flexible memory, but always handled via stack proxy like Box<T>),
    • static (most commonly used as resting place for str part of &str),
    • code (where bitcode of your functions reside).
  • Most tricky part is tied to how stack evolves, which is our focus.

1 For fixed-size values stack is trivially manageable: take a few bytes more while you need them, discarded once you leave. However, giving out pointers to these transient locations form the very essence of why lifetimes exist; and are the subject of the rest of this chapter.

Variables S(1) S(1) Variables 变量
let t = S(1);
  • Reserves memory location with name t of type S and the value S(1) stored inside.
  • If declared with let that location lives on stack. 1
  • Note the linguistic ambiguity, in the term variable, it can mean the:
    1. name of the location in the source file ("rename that variable"),
    2. location in a compiled app, 0x7 ("tell me the address of that variable"),
    3. value contained within, S(1) ("increment that variable").
  • Specifically towards the compiler t can mean location of t, here 0x7, and value within t, here S(1).

1 Compare above, true for fully synchronous code, but async stack frame might placed it on heap via runtime.

Move Semantics S(1) Moves 移动
let a = t;
  • This will move value within t to location of a, or copy it, if S is Copy.
  • After move location t is invalid and cannot be read anymore.
    • Technically the bits at that location are not really empty, but undefined.
    • If you still had access to t (via unsafe) they might still look like valid S, but any attempt to use them as valid S is undefined behavior.
  • We do not cover Copy types explicitly here. They change the rules a bit, but not much:
    • They won't be dropped.
    • They never leave behind an 'empty' variable location.
Type Safety M { … } Type Safety 类型安全
let c: S = M::new();
  • The type of a variable serves multiple important purposes, it:
    1. dictates how the underlying bits are to be interpreted,
    2. allows only well-defined operations on these bits
    3. prevents random other values or bits from being written to that location.
  • Here assignment fails to compile since the bytes of M::new() cannot be converted to form of type S.
  • Conversions between types will always fail in general, unless explicit rule allows it (coercion, cast, …).
Scope & Drop S(1) C(2) S(2) S(3) Scope & Drop 范围和丢弃
{
    let mut c = S(2);
    c = S(3);  // <- Drop called on `c` before assignment.
    let t = S(1);
    let a = t;
}   // <- Scope of `a`, `t`, `c` ends here, drop called on `a`, `c`.
  • Once the 'name' of a non-vacated variable goes out of (drop-)scope, the contained value is dropped.
    • Rule of thumb: execution reaches point where name of variable leaves {}-block it was defined in
    • In detail more tricky, esp. temporaries, …
  • Drop also invoked when new value assigned to existing variable location.
  • In that case Drop::drop() is called on the location of that value.
    • In the example above drop() is called on a, twice on c, but not on t.
  • Most non-Copy values get dropped most of the time; exceptions include mem::forget(), Rc cycles, abort().
Stack Frame S(1) Function Boundaries
fn f(x: S) { … }

let a = S(1); // <- We are here
f(a);
  • When a function is called, memory for parameters (and return values) are reserved on stack.1
  • Here before f is invoked value in a is moved to 'agreed upon' location on stack, and during f works like 'local variable' x.

1 Actual location depends on calling convention, might practically not end up on stack at all, but that doesn't change mental model.

S(1) Nested Functions
fn f(x: S) {
    if once() { f(x) } // <- We are here (before recursion)
}

let a = S(1);
f(a);
  • Recursively calling functions, or calling other functions, likewise extends the stack frame.
  • Nesting too many invocations (esp. via unbounded recursion) will cause stack to grow, and eventually to overflow, terminating the app.
Validity of Variables S(1) M { } Repurposing Memory
fn f(x: S) {
    if once() { f(x) }
    let m = M::new() // <- We are here (after recursion)
}

let a = S(1);
f(a);
  • Stack that previously held a certain type will be repurposed across (even within) functions.
  • Here, recursing on f produced second x, which after recursion was partially reused for m.

Key take away so far, there are multiple ways how memory locations that previously held a valid value of a certain type stopped doing so in the meantime. As we will see shortly, this has implications for pointers.

Reference Types   S(1) 0x3 References as Pointers
let a = S(1);
let r: &S = &a;
  • A reference type such as &S or &mut S can hold the location of some s.
  • Here type &S, bound as name r, holds location of variable a (0x3), that must be type S, obtained via &a.
  • If you think of variable c as specific location, reference r is a switchboard for locations.
  • The type of the reference, like all other types, can often be inferred, so we might omit it from now on:
    let r: &S = &a;
    let r = &a;
    
(Mutable) References   S(2) 0x3 S(1) Access to Non-Owned Memory
let mut a = S(1);
let r = &mut a;
let d = r.clone();  // Valid to clone (or copy) from r-target.
*r = S(2);          // Valid to set new S value to r-target.
  • References can read from (&S) and also write to (&mut S) locations they point to.
  • The dereference *r means to use the location r points to (not the location of or value within r itself)
  • In the example, clone d is created from *r, and S(2) written to *r.
    • We assume S implements Clone, and r.clone() clones target-of-r, not r itself.
    • On assignment *r = … old value in location also dropped (not shown above).
  S(2) 0x3 M { x } References Guard Referents
let mut a = …;
let r = &mut a;
let d = *r;       // Invalid to move out value, `a` would be empty.
*r = M::new();    // invalid to store non S value, doesn't make sense.
  • While bindings guarantee to always hold valid data, references guarantee to always point to valid data.
  • Esp. &mut T must provide same guarantees as variables, and some more as they can't dissolve the target:
    • They do not allow writing invalid data.
    • They do not allow moving out data (would leave target empty w/o owner knowing).
  C(2) 0x3 Raw Pointers
let p: *const S = questionable_origin();
  • In contrast to references, pointers come with almost no guarantees.
  • They may point to invalid or non-existent data.
  • Dereferencing them is unsafe, and treating an invalid *p as if it were valid is undefined behavior.
C(2) 0x3 "Lifetime" of Things
  • Every entity in a program has some (temporal / spatial) extent where it is relevant, i.e., alive.
  • Loosely speaking, this alive time can be1
    1. the LOC (lines of code) where an item is available (e.g., a module name).
    2. the LOC between when a location is initialized with a value, and when the location is abandoned.
    3. the LOC between when a location is first used in a certain way, and when that usage stops.
    4. the LOC (or actual time) between when a value is created, and when that value is dropped.
  • Within the rest of this section, we will refer to the items above as the:
    1. scope of that item, irrelevant here.
    2. scope of that variable or location.
    3. lifetime2 of that usage.
    4. lifetime of that value, might be useful when discussing open file descriptors, but also irrelevant here.
  • Likewise, lifetime parameters in code, e.g., r: &'a S, are
    • concerned with LOC any location r points to needs to be accessible or locked;
    • unrelated to the 'existence time' (as LOC) of r itself (well, it needs to exist shorter, that's it).
  • &'static S means address must be valid during all lines of code.

1 There is sometimes ambiguity in the docs differentiating the various scopes and lifetimes. We try to be pragmatic here, but suggestions are welcome.

2 Live lines might have been a more appropriate term …

  S(0) S(1) S(2) 0xa Meaning of r: &'c S
  • Assume you got a r: &'c S from somewhere it means:
    • r holds an address of some S,
    • any address r points to must and will exist for at least 'c,
    • the variable r itself cannot live longer than 'c.
  S(0) S(3) S(2) 0x6 Typelikeness of Lifetimes
{
    let b = S(3);
    {
        let c = S(2);
        let r: &'c S = &c;      // Does not quite work since we can't name lifetimes of local
        {                       // variables in a function body, but very same principle applies
            let a = S(0);       // to functions next page.

            r = &a;             // Location of `a` does not live sufficient many lines -> not ok.
            r = &b;             // Location of `b` lives all lines of `c` and more -> ok.
        }
    }
}
  • Assume you got a mut r: &mut 'c S from somewhere.
    • That is, a mutable location that can hold a mutable reference.
  • As mentioned, that reference must guard the targeted memory.
  • However, the 'c part, like a type, also guards what is allowed into r.
  • Here assiging &b (0x6) to r is valid, but &a (0x3) would not, as only &b lives equal or longer than &c.
  S(0)   S(2) 0x6 S(4) Borrowed State
let mut b = S(0);
let r = &mut b;

b = S(4);   // Will fail since `b` in borrowed state.

print_byte(r);
  • Once the address of a variable is taken via &b or &mut b the variable is marked as borrowed.
  • While borrowed, the content of the address cannot be modified anymore via original binding b.
  • Once address taken via &b or &mut b stops being used (in terms of LOC) original binding b works again.
S(0) S(1) S(2) ? 0x6 0xa Function Parameters
fn f(x: &S, y:&S) -> &u8 { … }

let b = S(1);
let c = S(2);

let r = f(&b, &c);
  • When calling functions that take and return references two interesting things happen:
    • The used local variables are placed in a borrowed state,
    • But it is during compilation unknown which address will be returned.
S(0) S(1) S(2) ? 0x6 0xa Problem of 'Borrowed' Propagation
let b = S(1);
let c = S(2);

let r = f(&b, &c);

let a = b;   // Are we allowed to do this?
let a = c;   // Which one is _really_ borrowed?

print_byte(r);
  • Since f can return only one address, not in all cases b and c need to stay locked.
  • In many cases we can get quality-of-life improvements.
    • Notably, when we know one parameter couldn't have been used in return value anymore.
  S(1) S(1) S(2) y + _ 0x6 0xa Lifetimes Propagate Borrowed State
fn f<'b, 'c>(x: &'b S, y: &'c S) -> &'c u8 { … }

let b = S(1);
let c = S(2);

let r = f(&b, &c); // We know returned reference is `c`-based, which must stay locked,
                   // while `b` is free to move.

let a = b;

print_byte(r);
  • Lifetime parameters in signatures, like 'c above, solve that problem.
  • Their primary purpose is:
    • outside the function, to explain based on which input address an output address could be generated,
    • within the function, to guarantee only addresses that live at least 'c are assigned.
  • The actual lifetimes 'b, 'c are transparently picked by the compiler at call site, based on the borrowed variables the developer gave.
  • They are not equal to the scope (which would be LOC from initialization to destruction) of b or c, but only a minimal subset of their scope called lifetime, that is, a minmal set of LOC based on how long b and c need to be borrowed to perform this call and use the obtained result.
  • In some cases, like if f had 'c: 'b instead, we still couldn't distinguish and both needed to stay locked.
S(2) S(1) S(2) y + 1 0x6 0xa Unlocking
let mut c = S(2);

let r = f(&c);
let s = r;
                    // <- Not here, `s` prolongs locking of `c`.

print_byte(s);

let a = c;          // <- But here, no more use of `r` or `s`.


  • A variable location is unlocked again once the last use of any reference that may point to it ends.
      S(1) 0x2 0x6 0x2 References to References
// Return short ('b) reference
fn f1sr<'b, 'a>(rb: &'b     &'a     S) -> &'b     S { *rb }
fn f2sr<'b, 'a>(rb: &'b     &'a mut S) -> &'b     S { *rb }
fn f3sr<'b, 'a>(rb: &'b mut &'a     S) -> &'b     S { *rb }
fn f4sr<'b, 'a>(rb: &'b mut &'a mut S) -> &'b     S { *rb }

// Return short ('b) mutable reference.
// f1sm<'b, 'a>(rb: &'b     &'a     S) -> &'b mut S { *rb } // M
// f2sm<'b, 'a>(rb: &'b     &'a mut S) -> &'b mut S { *rb } // M
// f3sm<'b, 'a>(rb: &'b mut &'a     S) -> &'b mut S { *rb } // M
fn f4sm<'b, 'a>(rb: &'b mut &'a mut S) -> &'b mut S { *rb }

// Return long ('a) reference.
fn f1lr<'b, 'a>(rb: &'b     &'a     S) -> &'a     S { *rb }
// f2lr<'b, 'a>(rb: &'b     &'a mut S) -> &'a     S { *rb } // L
fn f3lr<'b, 'a>(rb: &'b mut &'a     S) -> &'a     S { *rb }
// f4lr<'b, 'a>(rb: &'b mut &'a mut S) -> &'a     S { *rb } // L

// Return long ('a) mutable reference.
// f1lm<'b, 'a>(rb: &'b     &'a     S) -> &'a mut S { *rb } // M
// f2lm<'b, 'a>(rb: &'b     &'a mut S) -> &'a mut S { *rb } // M
// f3lm<'b, 'a>(rb: &'b mut &'a     S) -> &'a mut S { *rb } // M
// f4lm<'b, 'a>(rb: &'b mut &'a mut S) -> &'a mut S { *rb } // L

// Now assume we have a `ra` somewhere
let mut ra: &'a mut S = …;

let rval = f1sr(&&*ra);       // OK
let rval = f2sr(&&mut *ra);
let rval = f3sr(&mut &*ra);
let rval = f4sr(&mut ra);

//  rval = f1sm(&&*ra);       // Would be bad, since rval would be mutable
//  rval = f2sm(&&mut *ra);   // reference obtained from broken mutability
//  rval = f3sm(&mut &*ra);   // chain.
let rval = f4sm(&mut ra);

let rval = f1lr(&&*ra);
//  rval = f2lr(&&mut *ra);   // If this worked we'd have `rval` and `ra` …
let rval = f3lr(&mut &*ra);
//  rval = f4lr(&mut ra);     // … now (mut) aliasing `S` in compute below.

//  rval = f1lm(&&*ra);       // Same as above, fails for mut-chain reasons.
//  rval = f2lm(&&mut *ra);   //                    "
//  rval = f3lm(&mut &*ra);   //                    "
//  rval = f4lm(&mut ra);     // Same as above, fails for aliasing reasons.

// Some fictitious place where we use `ra` and `rval`, both alive.
compute(ra, rval);

Here (M) means compilation fails because mutability error, (L) lifetime error. Also, dereference *rb not strictly necessary, just added for clarity.

  • f_sr cases always work, short reference (only living 'b) can always be produced.
  • f_sm cases usually fail simply because mutable chain to S needed to return &mut S.
  • f_lr cases can fail because returning &'a S from &'a mut S to caller means there would now exist two references (one mutable) to same S which is illegal.
  • f_lm cases always fail for combination of reasons above.
S(1) Drop and _
{
    let f = |x, y| (S(x), S(y)); // Function returning two 'Droppables'.

    let (    x1, y) = f(1, 4);  // S(1) - Scope   S(4) - Scope
    let (    x2, _) = f(2, 5);  // S(2) - Scope   S(5) - Immediately
    let (ref x3, _) = f(3, 6);  // S(3) - Scope   S(6) - Scope

    println!("…");
}

Here Scope means contained value lives until end of scope, i.e., past the println!().

  • Functions or expressions producing movable values must be handled by callee.
  • Values stores in 'normal' bindings are kept until end of scope, then dropped.
  • Values stored in _ bindings are usually dropped right away.
  • However, sometimes references (e.g., ref x3) can keep value (e.g., the tuple (S(3), S(6))) around for longer, so S(6), being part of that tuple can only be dropped once reference to its S(3) sibling disappears).

↕️ Examples expand by clicking.
↕️ 单击展开示例。

 

Memory Layout 内存布局url

Byte representations of common types.
常见类型的字节表示。

Basic Types 基本类型url

Essential types built into the core of the language.
语言核心中内置的基本类型。

Boolean REF and Numeric Types REF
布尔 REF 和数字类型 REF
url

bool u8, i8 u16, i16 u32, i32 u64, i64 u128, i128 usize, isize Same as ptr on platform.
平台上与 ptr 相同。
f16 🚧 f32 f64 f128 🚧
 
Type 类型Max Value 最大值
u8255
u1665_535
u324_294_967_295
u6418_446_744_073_709_551_615
u128340_282_366_920_938_463_463_374_607_431_768_211_455
usizeDepending on platform pointer size, same as u16, u32, or u64.
根据平台指针大小,与 u16 相同, u32u64
TypeMax Value
i8127
i1632_767
i322_147_483_647
i649_223_372_036_854_775_807
i128170_141_183_460_469_231_731_687_303_715_884_105_727
isizeDepending on platform pointer size, same as i16, i32, or i64.
 
TypeMin Value
i8-128
i16-32_768
i32-2_147_483_648
i64-9_223_372_036_854_775_808
i128-170_141_183_460_469_231_731_687_303_715_884_105_728
isizeDepending on platform pointer size, same as i16, i32, or i64.
TypeMax valueMin pos valueMax lossless integer1
f16 🚧65536.0 ??2048 ?
f323.40 ⋅ 10 383.40 ⋅ 10 -3816_777_216
f641.79 ⋅ 10 3082.23 ⋅ 10 -3089_007_199_254_740_992
f128 🚧???

1 The maximum integer M so that all other integers 0 <= X <= M can be losslessly represented in that type. In other words, there might be larger integers that could still be represented losslessly (e.g., 65536 for f16), but up until that value a lossless representation is guaranteed.

 

Float values approximated for visual clarity. Negative limits are values multipled with -1.

Sample bit representation* for a f32:

S E E E E E E E E F F F F F F F F F F F F F F F F F F F F F F F
 

Explanation:

f32S (1)E (8)F (23)Value
Normalized number±1 to 254any±(1.F)2 * 2E-127
Denormalized number±0non-zero±(0.F)2 * 2-126
Zero±00±0
Infinity±2550±∞
NaN±255non-zeroNaN
 

Similarly, for f64 types this would look like:

f64S (1)E (11)F (52)Value
Normalized number±1 to 2046any±(1.F)2 * 2E-1023
Denormalized number±0non-zero±(0.F)2 * 2-1022
Zero±00±0
Infinity±20470±∞
NaN±2047non-zeroNaN
* Float types follow IEEE 754-2008 and depend on platform endianness.
Cast1GivesNote
3.9_f32 as u83Truncates, consider x.round() first.
314_f32 as u8255Takes closest available number.
f32::INFINITY as u8255Same, treats INFINITY as really large number.
f32::NAN as u80-
_314 as u858Truncates excess bits.
_257 as i81Truncates excess bits.
_200 as i8-56Truncates excess bits, MSB might then also signal negative.
Operation1GivesNote
200_u8 / 0_u8Compile error.-
200_u8 / _0 d, rPanic.Regular math may panic; here: division by zero.
200_u8 + 200_u8Compile error.-
200_u8 + _200 dPanic.Consider checked_, wrapping_, … instead. STD
200_u8 + _200 r144In release mode this will overflow.
-128_i8 * -1Compile error.Would overflow (128_i8 doesn't exist).
-128_i8 * _1neg dPanic.-
-128_i8 * _1neg r-128Overflows back to -128 in release mode.
1_u8 / 2_u80Other integer division truncates.
0.8_f32 + 0.1_f320.90000004-
1.0_f32 / 0.0_f32f32::INFINITY-
0.0_f32 / 0.0_f32f32::NAN-
x < f32::NANfalseNAN comparisons always return false.
x > f32::NANfalseNAN comparisons always return false.
f32::NAN == f32::NANfalseUse f32::is_nan() STD instead.

1 Expression _100 means anything that might contain the value 100, e.g., 100_i32, but is opaque to compiler.
1 表达式 _100 表示可能包含值 100 的任何内容,例如, 100_i32 ,但对编译器不透明。

d Debug build.  d 调试构建。
r Release build. 发布构建。

 

Textual Types REF 文本类型 REF url

char Any Unicode scalar. 任何 Unicode 标量。 str U T F - 8 … unspecified times
U T F - 8 … 未指定次数
Rarely seen alone, but as &str instead.
很少单独出现,而是作为 &str
 
TypeDescription
charAlways 4 bytes and only holds a single Unicode scalar value 🔗.
strAn u8-array of unknown length guaranteed to hold UTF-8 encoded code points.
一个长度未知的 u8 数组,保证包含 UTF-8 编码的代码点。
CharsDescription
let c = 'a';Often a char (unicode scalar) can coincide with your intuition of character.
let c = '❤';It can also hold many Unicode symbols.
let c = '❤️';But not always. Given emoji is two char (see Encoding) and can't 🛑 be held by c.1
c = 0xffff_ffff;Also, chars are not allowed 🛑 to hold arbitrary bit patterns.
1 Fun fact, due to the Zero-width joiner (⨝) what the user perceives as a character can get even more unpredictable: 👨‍👩‍👧 is in fact 5 chars 👨⨝👩⨝👧, and rendering engines are free to either show them fused as one, or separately as three, depending on their abilities.
 
StringsDescription
let s = "a";A str is usually never held directly, but as &str, like s here.
let s = "❤❤️";It can hold arbitrary text, has variable length per c., and is hard to index.

let s = "I ❤ Rust";
let t = "I ❤️ Rust";

VariantMemory Representation2
s.as_bytes()49 20 e2 9d a4 20 52 75 73 74 3
t.as_bytes()49 20 e2 9d a4 ef b8 8f 20 52 75 73 74 4
s.chars()149 00 00 00 20 00 00 00 64 27 00 00 20 00 00 00 52 00 00 00 75 00 00 00 73 00
t.chars()149 00 00 00 20 00 00 00 64 27 00 00 0f fe 01 00 20 00 00 00 52 00 00 00 75 00
 
1 Result then collected into array and transmuted to bytes.
2 Values given in hex, on x86.
3 Notice how , having Unicode Code Point (U+2764), is represented as 64 27 00 00 inside the char, but got UTF-8 encoded to e2 9d a4 in the str.
4 Also observe how the emoji Red Heart ❤️, is a combination of and the U+FE0F Variation Selector, thus t has a higher char count than s.
 

⚠️ For what seem to be browser bugs Safari and Edge render the hearts in Footnote 3 and 4 wrong, despite being able to differentiate them correctly in s and t above.

 

Custom Typesurl

Basic types definable by users. Actual layout REF is subject to representation; REF padding can be present.

T T Sized  大小 T: ?Sized T Maybe DST  也许 DST [T; n] T T T … n times
T T T … n 次
Fixed array of n elements.
修复了包含 n 个元素的数组。
[T] T T T … unspecified times
T T T … 未指定次数
Slice type of unknown-many elements. Neither
未知数量元素的切片类型。既不

Sized (nor carries len information), and most
Sized (也不携带 len 信息),而大多数

often lives behind reference as &[T].
通常作为 &[T] 的引用存在。
struct S; Zero-Sized  零大小 (A, B, C) A B C or maybe 或者 B A C Unless a representation is forced
除非强制表示

(e.g., via #[repr(C)]), type layout
(例如,通过 #[repr(C)] ),输入布局

unspecified. 未指定。
struct S { b: B, c: C } B C or maybe 或者 C B Compiler may also add padding.
编译器也可能添加填充。

Also note, two types A(X, Y) and B(X, Y) with exactly the same fields can still have differing layout; never transmute() STD without representation guarantees.
请注意,即使具有完全相同字段的两种类型 A(X, Y)B(X, Y) 仍可能具有不同的布局;永远不要在没有表示保证的情况下 transmute() STD

 

These sum types hold a value of one of their sub types:
这些总和类型保存其子类型之一的值:

enum E { A, B, C } Tag A exclusive or 异或 Tag B exclusive or 异或 Tag C Safely holds A or B or C, also
安全地保存 A 或 B 或 C,也

called 'tagged union', though
称为“标记联合”,尽管

compiler may squeeze tag
编译器可能会压缩标签

into 'unused' bits.  转换为“未使用”的位。
union { … } A unsafe or 不安全或 B unsafe or 不安全或 C Can unsafely reinterpret
可以不安全地重新解释

memory. Result might  内存。结果可能
be undefined.  是未定义的。

References & Pointers 引用和指针url

References give safe access to 3rd party memory, raw pointers unsafe access. The corresponding mut types have an identical data layout to their immutable counterparts.
引用提供对第三方内存的安全访问,原始指针访问。相应的类型与其不可变对应类型具有相同的数据布局。

&'a T ptr2/4/8 meta2/4/8 | T Must target some valid t of T,
必须针对一些有效的 t 目标 T

and any such target must exist for
任何这样的目标必须存在

at least 'a.
至少 'a
*const T ptr2/4/8 meta2/4/8 No guarantees.  不提供任何保证。

Pointer Meta 指针元数据url

Many reference and pointer types can carry an extra field, pointer metadata. STD It can be the element- or byte-length of the target, or a pointer to a vtable. Pointers with meta are called fat, otherwise thin.
许多引用和指针类型可以携带额外的字段,指针元数据。 STD 它可以是目标的元素长度或字节长度,或者是指向虚函数表的指针。带有元数据的指针称为 fat,否则称为 thin。

&'a T ptr2/4/8 | T No meta for  没有元数据
sized target. 大小目标。
(pointer is thin). (指针很细)。
&'a T ptr2/4/8 len2/4/8 | T If T is a DST struct such as
如果 T 是一个 DST struct ,比如

S { x: [u8] } meta field len is
S { x: [u8] } 元字段 len

count of dyn. sized content.
动态大小内容的计数。
&'a [T] ptr2/4/8 len2/4/8 | T T Regular slice reference (i.e., the
常规切片引用(即,

reference type of a slice type [T])
切片类型的引用类型 [T] )

often seen as &[T] if 'a elided.
通常被视为 &[T] 如果 'a 被省略。
&'a str ptr2/4/8 len2/4/8 | U T F - 8 String slice reference (i.e., the
字符串切片引用(即,

reference type of string type str),
字符串类型的引用类型 str ),

with meta len being byte length.
具有元数据 len 的字节长度。

&'a dyn Trait ptr2/4/8 ptr2/4/8 | T |
*Drop::drop(&mut T)
size
align
*Trait::f(&T, …)
*Trait::g(&T, …)
Meta points to vtable, where *Drop::drop(), *Trait::f(), … are pointers to their respective impl for T.
Meta 指向 vtable,其中 *Drop::drop()*Trait::f() ,...是它们各自 T 的指针。

Closures 闭包url

Ad-hoc functions with an automatically managed data block capturing REF, 1 environment where closure was defined. For example, if you had:
使用自动管理的数据块捕获 REF , 1 环境的即席函数,其中闭包被定义。例如,如果您有:

let y = ...;
let z = ...;

with_closure(move |x| x + y.f() + z); // y and z are moved into closure instance (of type C1)
with_closure(     |x| x + y.f() + z); // y and z are pointed at from closure instance (of type C2)

Then the generated, anonymous closures types C1 and C2 passed to with_closure() would look like:
然后传递给 with_closure() 的生成的匿名闭包类型 C1C2 看起来像:

move |x| x + y.f() + z Y Z Anonymous closure type C1
匿名闭包类型 C1
|x| x + y.f() + z ptr2/4/8 ptr2/4/8 Anonymous closure type C2
匿名闭包类型 C2
| Y | Z

Also produces anonymous fn such as fc1(C1, X) or fc2(&C2, X). Details depend on which FnOnce, FnMut, Fn ... is supported, based on properties of captured types.
还会生成匿名 fn ,如 fc1(C1, X)fc2(&C2, X) 。详细信息取决于支持哪些 FnOnceFnMutFn ...,基于捕获类型的属性。

1 A bit oversimplified a closure is a convenient-to-write 'mini function' that accepts parameters but also needs some local variables to do its job. It is therefore a type (containing the needed locals) and a function. 'Capturing the environment' is a fancy way of saying that and how the closure type holds on to these locals, either by moved value, or by pointer. See Closures in APIs for various implications.
1 有点过于简化,闭包是一个方便编写的“迷你函数”,它接受参数但也需要一些本地变量来完成其工作。因此,它是一种类型(包含所需的本地变量)和一个函数。'捕获环境' 是一种花哨的说法,说明闭包类型如何保留这些本地变量,可以通过移动值或指针。请参阅 API 中的闭包 ,了解各种含义。

Standard Library Types 标准库类型url

Rust's standard library combines the above primitive types into useful types with special semantics, e.g.:
Rust 标准库将上述原始类型组合成具有特殊语义的有用类型,例如:

UnsafeCell<T> STD T Magic type allowing  魔法类型允许
aliased mutability. 别名可变性。
Cell<T> STD T Allows T's 允许 T
to move in 移动到
and out. 和输出。
RefCell<T> STD borrowed T Also support dynamic 也支持动态
borrowing of T. Like Cell this
借用 T 。像 Cell 这样

is Send, but not Sync.
Send ,但不是 Sync
ManuallyDrop<T> STD T Prevents T::drop() from 防止 T::drop() 发生
being called. 被调用。
AtomicUsize STD usize2/4/8 Other atomic similarly. 其他原子同样。 Option<T> STD Tag or  Tag T Tag may be omitted for
标签可能被省略

certain T, e.g., NonNull.STD
某些 T,例如, NonNull . STD
Result<T, E> STD Tag E or  Tag T Either some error E or value
要么出现错误 E ,要么是值

of T.  T 的。
MaybeUninit<T> STD U̼̟̔͛n̥͕͐͞d̛̲͔̦̳̑̓̐e̱͎͒̌fị̱͕̈̉͋ne̻̅ḓ̓ unsafe or 不安全或 T Uninitialized memory or 未初始化的内存或
some T. Only legal way
一些 T 。只有合法的方式

to work with uninit data.
与未初始化数据一起工作。

🛑 All depictions are for illustrative purposes only. The fields should exist in latest stable, but Rust makes no guarantees about their layouts, and you must not attempt to unsafely access anything unless the docs allow it.
🛑 所有描绘仅供参考。这些字段应该存在于最新的 stable 中,但 Rust 不能保证它们的布局,除非文档允许,否则不得尝试不安全地访问任何内容。

 

Order-Preserving Collections
有序集合
url

Box<T> STD ptr2/4/8 meta2/4/8 | T For some T stack proxy may carry
对于一些 T 堆栈代理可能会携带

meta (e.g., Box<[T]>). 元数据(例如, Box<[T]> )。
Vec<T> STD ptr2/4/8 len2/4/8 capacity2/4/8 |
T T … len
T T … 长度
capacity ← 容量 →
Regular growable array vector of single type.
单一类型的常规可增长数组向量。
LinkedList<T> STD🝖 head2/4/8 tail2/4/8 len2/4/8 | | next2/4/8 prev2/4/8 T Elements head and tail both null or point to nodes on
元素 headtailnull 或指向节点

the heap. Each node can point to its prev and next node.
堆。每个节点可以指向其 prevnext 节点。

Eats your cache (just look at the thing!); don't use unless
吃掉你的缓存(只看看这个东西!);除非必要,否则不要使用

you evidently must. 🛑
你显然必须。 🛑
VecDeque<T> STD head2/4/8 len2/4/8 ptr2/4/8 capacity2/4/8 |
T … empty … T⁣H
T … 空 … T⁣H
capacity ← 容量 →
Index head selects in array-as-ringbuffer. This means content may be
索引 head 在数组作为环形缓冲区中选择。这意味着内容可能会

non-contiguous and empty in the middle, as exemplified above.
非连续和中间为空,如上所示。
 

Other Collections 其他集合url

HashMap<K, V> STD bmask2/4/8 ctrl2/4/8 left2/4/8 len2/4/8 | K:V K:VK:VK:V Oversimplified! 过于简化! Stores keys and values on heap according to hash value, SwissTable
根据哈希值在堆上存储键和值,SwissTable

implementation via hashbrown. HashSet STD identical to HashMap,
通过 hashbrown 实现。 HashSet STDHashMap 相同,

just type V disappears. Heap view grossly oversimplified. 🛑
只需键入 V 即可消失。堆视图过于简化。 🛑
BinaryHeap<T> STD ptr2/4/8 capacity2/4/8 len2/4/8 |
T⁣0 T⁣1 T⁣1 T⁣2 T⁣2 … len
T⁣0 T⁣1 T⁣1 T⁣2 T⁣2 … 长度
capacity ← 容量 →
Heap stored as array with 2N elements per layer. Each T
堆存储为每层具有 2N 个元素的数组。每个 T

can have 2 children in layer below. Each T larger than its
在下一层可以有 2 个子节点。每个 T 都比其

children. children。

Owned Strings 拥有的字符串url

String STD ptr2/4/8 capacity2/4/8 len2/4/8 |
U T F - 8 … len
U T F - 8 … 长度
capacity ← 容量 →
Observe how String differs from &str and &[char].
观察 String&str&[char] 之间的区别。
CString STD ptr2/4/8 len2/4/8 |
A B C … len …
A B C … 长度 …
NUL-terminated but w/o NUL in middle.
以 NUL 结尾但中间没有 NUL。
OsString STD Platform Defined  平台定义 |
/
Encapsulates how operating system
封装了操作系统如何

represents strings (e.g., WTF-8 on
代表字符串(例如,WTF-8)

Windows).
PathBuf STD OsString |
/
Encapsulates how operating system
封装了操作系统如何

represents paths. 代表路径。
 

Shared Ownership 共享所有权url

If the type does not contain a Cell for T, these are often combined with one of the Cell types above to allow shared de-facto mutability.
如果类型不包含 Cell 用于 T ,通常会与上述其中一种 Cell 类型结合,以允许共享的事实上的可变性。

Rc<T> STD ptr2/4/8 meta2/4/8
| strng2/4/8 weak2/4/8 T
Share ownership of T in same thread. Needs nested Cell
在同一线程中共享 T 的所有权。需要嵌套 Cell

or RefCellto allow mutation. Is neither Send nor Sync.
或者 RefCell 允许变异。既不是 Send 也不是 Sync
Arc<T> STD ptr2/4/8 meta2/4/8
| strng2/4/8 weak2/4/8 T
Same, but allow sharing between threads IF contained
相同,但允许在包含的情况下在线程之间共享

T itself is Send and Sync.
T 本身是 SendSync

Mutex<T> STD / RwLock<T> STD inner poison2/4/8 T Inner fields depend on platform. Needs to be
内部字段取决于平台。需要进行

held in Arc to be shared between decoupled
Arc 中保存以便在解耦之间共享

threads, or via scope() STD for scoped threads.
线程,或通过 scope() STD 进行作用域线程。
Cow<'a, T> STD Tag T::Owned or  Tag ptr2/4/8
| T
Holds read-only reference to
保存只读引用

some T, or owns its ToOwned STD
一些 T ,或拥有它的 ToOwned STD

analog. 模拟。

Standard Library 标准库url

One-Liners 一行代码url

Snippets that are common, but still easy to forget. See Rust Cookbook 🔗 for more.
常见但容易被遗忘的代码片段。查看 Rust Cookbook 🔗 了解更多。

Intent 意图Snippet 片段
Concatenate strings (any Display that is). STD 1 '21
连接字符串(任何 Display )。 STD 1 '21
format!("{x}{y}")
Append string (any Display to any Write). '21 STD
追加字符串(任何 Display 到任何 Write )。 '21 STD
write!(x, "{y}")
Split by separator pattern. STD 🔗
按分隔符模式拆分。 STD 🔗
s.split(pattern)
     … with &str …与 &str s.split("abc")
     … with char …与 char s.split('/')
     … with closure … 闭包s.split(char::is_numeric)
Split by whitespace. STD
按空格分割。 STD
s.split_whitespace()
Split by newlines. STD 按换行符拆分。 STD s.lines()
Split by regular expression. 🔗 2
按正则表达式拆分。 🔗 2
Regex::new(r"\s")?.split("one two three")

1 Allocates; if x or y are not going to be used afterwards consider using write! or std::ops::Add.
1 分配;如果 xy 之后不会被使用,请考虑使用 write!std::ops::Add

2 Requires regex crate.
2 需要 regex crate。

IntentSnippet
Create a new file STDFile::create(PATH)?
     Same, via OpenOptionsOpenOptions::new().create(true).write(true).truncate(true).open(PATH)?
Read file as String STDread_to_string(path)?
IntentSnippet
Macro w. variable argumentsmacro_rules! var_args { ($($args:expr),*) => {{ }} }
     Using args, e.g., calling f multiple times.     $( f($args); )*
Starting TypeResource
Option<T> -> …See the Type-Based Cheat Sheet
Result<T, R> -> …See the Type-Based Cheat Sheet
Iterator<Item=T> -> …See the Type-Based Cheat Sheet
&[T] -> …See the Type-Based Cheat Sheet
Future<T> -> …See the Futures Cheat Sheet
IntentSnippet
Cleaner closure captureswants_closure({ let c = outer.clone(); move || use_clone(c) })
Fix inference in 'try' closuresiter.try_for_each(|x| { Ok::<(), Error>(()) })?;
Iterate and edit &mut [T] if T Copy.Cell::from_mut(mut_slice).as_slice_of_cells()
Get subslice with length.&original_slice[offset..][..length]
Canary so trait T is object safe.const _: Option<&dyn T> = None;

Thread Safety 线程安全url

Assume you hold some variables in Thread 1, and want to either move them to Thread 2, or pass their references to Thread 3. Whether this is allowed is governed by SendSTD and SyncSTD respectively:
假设您在线程 1 中持有一些变量,并希望将它们移动到线程 2,或者将它们的引用传递给线程 3。是否允许这样做取决于 Send STDSync STD 分别:

 

|
|
|
 Mutex<u32>
|
|
|
 Cell<u32>
|
|
|
 MutexGuard<u32>
|
|
|
 Rc<u32>
Thread 1 线程 1

 Mutex<u32>  Cell<u32>  MutexGuard<u32>  Rc<u32> Thread 2 线程 2

&Mutex<u32> &Cell<u32> &MutexGuard<u32> &Rc<u32> Thread 3 线程 3
 
Example 示例Explanation 解释
Mutex<u32>Both Send and Sync. You can safely pass or lend it to another thread.
SendSync 都是线程安全的。您可以安全地将其传递或借给另一个线程。
Cell<u32>Send, not Sync. Movable, but its reference would allow concurrent non-atomic writes.
Send ,而不是 Sync 。可移动,但其引用将允许并发的非原子写入。
MutexGuard<u32>Sync, but not Send. Lock tied to thread, but reference use could not allow data race.
Sync ,但不是 Send 。锁绑定到线程,但引用使用不能允许数据竞争。
Rc<u32>Neither since it is easily clonable heap-proxy with non-atomic counters.
既不易克隆堆代理,也不带原子计数器。
 
Trait 特征Send!Send
SyncMost typesArc<T>1,2, Mutex<T>2
大多数类型... Arc<T> 1,2Mutex<T> 2
MutexGuard<T>1, RwLockReadGuard<T>1
!SyncCell<T>2, RefCell<T>2Rc<T>, &dyn Trait, *const T3

1 If T is Sync.
1 如果 TSync

2 If T is Send.
2 如果 TSend

3 If you need to send a raw pointer, create newtype struct Ptr(*const u8) and unsafe impl Send for Ptr {}. Just ensure you may send it.
3 如果您需要发送原始指针,请创建新类型 struct Ptr(*const u8)unsafe impl Send for Ptr {} 。只需确保您可以发送它。

Iterators 迭代器url

Processing elements in a collection.
在集合中处理元素。

There are, broadly speaking, four styles of collection iteration:
总的来说,有四种收集迭代的风格:

Style 样式Description 描述
for x in c { ... }Imperative, useful w. side effects, interdepend., or need to break flow early.
命令式,有用的,带有副作用,相互依赖,或需要提前中断流程。
c.iter().map().filter()Functional, often much cleaner when only results of interest.
功能性,通常在只关注结果时更清晰。
c_iter.next()Low-level, via explicit Iterator::next() STD invocation. 🝖
低级别,通过显式 Iterator::next() STD 调用。 🝖
c.get(n)Manual, bypassing official iteration machinery.
手动,绕过官方迭代机制。
 

Opinion 💬 — Functional style is often easiest to follow, but don't hesitate to use for if your .iter() chain turns messy. When implementing containers iterator support would be ideal, but when in a hurry it can sometimes be more practical to just implement .len() and .get() and move on with your life.
意见 💬 — 函数式风格通常最容易理解,但如果您的 .iter() 链变得混乱,请毫不犹豫地使用 for 。在实现容器时,迭代器支持是理想的,但在匆忙时,有时只实现 .len().get() 然后继续生活更为实际。

Basics

Assume you have a collection c of type C you want to use:

  • c.into_iter()1 — Turns collection c into an Iterator STD i and consumes2 c. Std. way to get iterator.
  • c.iter() — Courtesy method some collections provide, returns borrowing Iterator, doesn't consume c.
  • c.iter_mut() — Same, but mutably borrowing Iterator that allow collection to be changed.

The Iterator

Once you have an i:

  • i.next() — Returns Some(x) next element c provides, or None if we're done.

For Loops

  • for x in c {} — Syntactic sugar, calls c.into_iter() and loops i until None.

1 Requires IntoIterator STD for C to be implemented. Type of item depends on what C was.

2 If it looks as if it doesn't consume c that's because type was Copy. For example, if you call (&c).into_iter() it will invoke .into_iter() on &c (which will consume a copy of the reference and turn it into an Iterator), but the original c remains untouched.

Essentials

Let's assume you have a struct Collection<T> {} you authored. You should also implement:

  • struct IntoIter<T> {} — Create a struct to hold your iteration status (e.g., an index) for value iteration.
  • impl Iterator for IntoIter<T> {} — Implement Iterator::next() so it can produce elements.
Collection<T> IntoIter<T> Iterator Item = T;
 

At this point you have something that can behave as an Iterator, STD but no way of actually obtaining it. See the next tab for how that usually works.

Native Loop Support

Many users would expect your collection to just work in for loops. You need to implement:

  • impl IntoIterator for Collection<T> {} — Now for x in c {} works.
  • impl IntoIterator for &Collection<T> {} — Now for x in &c {} works.
  • impl IntoIterator for &mut Collection<T> {} — Now for x in &mut c {} works.
Collection<T> IntoIterator Item = T; To = IntoIter<T> Iterate over T. &Collection<T> IntoIterator Item = &T; To = Iter<T> Iterate over &T. &mut Collectn<T> IntoIterator Item = &mut T; To = IterMut<T> Iterate over &mut T.
 

As you can see, the IntoIterator STD trait is what actually connects your collection with the IntoIter struct you created in the previous tab. The two siblings of IntoIter (Iter and IterMut) are discussed in the next tab.

Shared & Mutable Iterators

In addition, if you want your collection to be useful when borrowed you should implement:

  • struct Iter<T> {} — Create struct holding &Collection<T> state for shared iteration.
  • struct IterMut<T> {} — Similar, but holding &mut Collection<T> state for mutable iteration.
  • impl Iterator for Iter<T> {} — Implement shared iteration.
  • impl Iterator for IterMut<T> {} — Implement mutable iteration.

Also you might want to add convenience methods:

  • Collection::iter(&self) -> Iter,
  • Collection::iter_mut(&mut self) -> IterMut.
Iter<T> Iterator Item = &T; IterMut<T> Iterator Item = &mut T;
 

The code for borrowing interator support is basically just a repetition of the previous steps with a slightly different types, e.g., &T vs T.

Iterator Interoperability

To allow 3rd party iterators to 'collect into' your collection implement:

  • impl FromIterator for Collection<T> {} — Now some_iter.collect::<Collection<_>>() works.
  • impl Extend for Collection<T> {} — Now c.extend(other) works.

In addition, also consider adding the extra traits from std::iter STD to your previous structs:

Collection<T> FromIterator Extend IntoIter<T> DoubleEndedIt… ExactSizeIt… FusedIterator Iter<T> DoubleEndedIt… ExactSizeIt… FusedIterator IterMut<T> DoubleEndedIt… ExactSizeIt… FusedIterator
 

Writing collections can be work. The good news is, if you followed all these steps your collections will feel like first class citizens.

Number Conversions 数字转换url

As-correct-as-it-currently-gets number conversions.
尽可能准确的数字转换。

↓ Have / Want →
↓ 拥有 / 想要 →
u8i128f32 / f64String 字符串
u8i128u8::try_from(x)? 1x as f32 3x.to_string()
f32 / f64x as u8 2x as f32x.to_string()
Stringx.parse::<u8>()?x.parse::<f32>()?x

1 If type true subset from() works directly, e.g., u32::from(my_u8).
1 如果类型为 true,则子集 from() 可直接使用,例如, u32::from(my_u8)

2 Truncating (11.9_f32 as u8 gives 11) and saturating (1024_f32 as u8 gives 255); c. below.
2 截断( 11.9_f32 as u8 得到 11 )和饱和( 1024_f32 as u8 得到 255 );请参见下文。

3 Might misrepresent number (u64::MAX as f32) or produce Inf (u128::MAX as f32).
3 可能会误传数字( u64::MAX as f32 )或产生 Infu128::MAX as f32 )。

 

Also see Casting- and Arithmetic Pitfalls for more things that can go wrong working with numbers.
另请参阅《类型转换和算术陷阱 》,了解更多在处理数字时可能出错的情况。

String Conversions 字符串转换url

If you want a string of type …
如果您想要一个类型为...的字符串

If you have x of type …
如果您有 x 类型…
Use this … 使用此 …
Stringx
CStringx.into_string()?
OsStringx.to_str()?.to_string()
PathBufx.to_str()?.to_string()
Vec<u8> 1String::from_utf8(x)?
&strx.to_string() i
&CStrx.to_str()?.to_string()
&OsStrx.to_str()?.to_string()
&Pathx.to_str()?.to_string()
&[u8] 1String::from_utf8_lossy(x).to_string()
If you have x of type …Use this …
StringCString::new(x)?
CStringx
OsStringCString::new(x.to_str()?)?
PathBufCString::new(x.to_str()?)?
Vec<u8> 1CString::new(x)?
&strCString::new(x)?
&CStrx.to_owned() i
&OsStrCString::new(x.to_os_string().into_string()?)?
&PathCString::new(x.to_str()?)?
&[u8] 1CString::new(Vec::from(x))?
*mut c_char 2unsafe { CString::from_raw(x) }
If you have x of type …Use this …
StringOsString::from(x) i
CStringOsString::from(x.to_str()?)
OsStringx
PathBufx.into_os_string()
Vec<u8> 1unsafe { OsString::from_encoded_bytes_unchecked(x) }
&strOsString::from(x) i
&CStrOsString::from(x.to_str()?)
&OsStrOsString::from(x) i
&Pathx.as_os_str().to_owned()
&[u8] 1unsafe { OsString::from_encoded_bytes_unchecked(x.to_vec()) }
If you have x of type …Use this …
StringPathBuf::from(x) i
CStringPathBuf::from(x.to_str()?)
OsStringPathBuf::from(x) i
PathBufx
Vec<u8> 1unsafe { PathBuf::from(OsString::from_encoded_bytes_unchecked(x)) }
&strPathBuf::from(x) i
&CStrPathBuf::from(x.to_str()?)
&OsStrPathBuf::from(x) i
&PathPathBuf::from(x) i
&[u8] 1unsafe { PathBuf::from(OsString::from_encoded_bytes_unchecked(x.to_vec())) }
If you have x of type …Use this …
Stringx.into_bytes()
CStringx.into_bytes()
OsStringx.into_encoded_bytes()
PathBufx.into_os_string().into_encoded_bytes()
Vec<u8> 1x
&strVec::from(x.as_bytes())
&CStrVec::from(x.to_bytes_with_nul())
&OsStrVec::from(x.as_encoded_bytes())
&PathVec::from(x.as_os_str().as_encoded_bytes())
&[u8] 1x.to_vec()
If you have x of type …Use this …
Stringx.as_str()
CStringx.to_str()?
OsStringx.to_str()?
PathBufx.to_str()?
Vec<u8> 1std::str::from_utf8(&x)?
&strx
&CStrx.to_str()?
&OsStrx.to_str()?
&Pathx.to_str()?
&[u8] 1std::str::from_utf8(x)?
If you have x of type …Use this …
StringCString::new(x)?.as_c_str()
CStringx.as_c_str()
OsStringx.to_str()?
PathBuf?,3
Vec<u8> 1,4CStr::from_bytes_with_nul(&x)?
&str?,3
&CStrx
&OsStr?
&Path?
&[u8] 1,4CStr::from_bytes_with_nul(x)?
*const c_char 1unsafe { CStr::from_ptr(x) }
If you have x of type …Use this …
StringOsStr::new(&x)
CString?
OsStringx.as_os_str()
PathBufx.as_os_str()
Vec<u8> 1unsafe { OsStr::from_encoded_bytes_unchecked(&x) }
&strOsStr::new(x)
&CStr?
&OsStrx
&Pathx.as_os_str()
&[u8] 1unsafe { OsStr::from_encoded_bytes_unchecked(x) }
If you have x of type …Use this …
StringPath::new(x) r
CStringPath::new(x.to_str()?)
OsStringPath::new(x.to_str()?) r
PathBufPath::new(x.to_str()?) r
Vec<u8> 1unsafe { Path::new(OsStr::from_encoded_bytes_unchecked(&x)) }
&strPath::new(x) r
&CStrPath::new(x.to_str()?)
&OsStrPath::new(x) r
&Pathx
&[u8] 1unsafe { Path::new(OsStr::from_encoded_bytes_unchecked(x)) }
If you have x of type …Use this …
Stringx.as_bytes()
CStringx.as_bytes()
OsStringx.as_encoded_bytes()
PathBufx.as_os_str().as_encoded_bytes()
Vec<u8> 1&x
&strx.as_bytes()
&CStrx.to_bytes_with_nul()
&OsStrx.as_encoded_bytes()
&Pathx.as_os_str().as_encoded_bytes()
&[u8] 1x
You wantAnd have xUse this …
*const c_charCStringx.as_ptr()

i Short form x.into() possible if type can be inferred.
如果类型可以被推断出来,则可以使用简短形式 x.into()

r Short form x.as_ref() possible if type can be inferred.
如果类型可以被推断出来,则可以使用简短形式 x.as_ref()

1 You must ensure x comes with a valid representation for the string type (e.g., UTF-8 data for a String).
1 您必须确保 x 包含有效的字符串类型表示(例如, String 的 UTF-8 数据)。

2 The c_char must have come from a previous CString. If it comes from FFI see &CStr instead.
2 这个 c_char 必须来自先前的 CString 。如果它来自 FFI,请参阅 &CStr

3 No known shorthand as x will lack terminating 0x0. Best way to probably go via CString.
3 没有已知的速记法,因为 x 将缺少终止 0x0 。可能最好的方法是通过 CString

4 Must ensure x actually ends with 0x0.
4 必须确保 x 实际上以 0x0 结尾。

String Output 字符串输出url

How to convert types into a String, or output them.
如何将类型转换为 String ,或输出它们。

Rust has, among others, these APIs to convert types to stringified output, collectively called format macros:
Rust 有这些 API 来将类型转换为字符串输出,统称为格式宏:

Macro Output 输出Notes 笔记
format!(fmt)StringBread-and-butter "to String" converter.
面包和黄油“转换为 String ”转换器。
print!(fmt)Console 控制台Writes to standard output.
写入标准输出。
println!(fmt)Console 控制台Writes to standard output.
写入标准输出。
eprint!(fmt)Console 控制台Writes to standard error.
写入标准错误。
eprintln!(fmt)Console 控制台Writes to standard error.
写入标准错误。
write!(dst, fmt)Buffer 缓冲区Don't forget to also use std::io::Write;
不要忘记也 use std::io::Write;
writeln!(dst, fmt)Buffer 缓冲区Don't forget to also use std::io::Write;
不要忘记也 use std::io::Write;
 
Method 方法Notes 笔记
x.to_string() STDProduces String, implemented for any Display type.
生成 String ,为任何 Display 类型实现。
 

Here fmt is string literal such as "hello {}", that specifies output (compare "Formatting" tab) and additional parameters.
这里的 fmt 是字符串文字,比如 "hello {}" ,用于指定输出(请参阅“格式”选项卡)和其他参数。

In format! and friends, types convert via trait Display "{}" STD or Debug "{:?}" STD , non exhaustive list:

TypeImplements
StringDebug, Display
CStringDebug
OsStringDebug
PathBufDebug
Vec<u8>Debug
&strDebug, Display
&CStrDebug
&OsStrDebug
&PathDebug
&[u8]Debug
boolDebug, Display
charDebug, Display
u8i128Debug, Display
f32, f64Debug, Display
!Debug, Display
()Debug
 

In short, pretty much everything is Debug; more special types might need special handling or conversion to Display.

Each argument designator in format macro is either empty {}, {argument}, or follows a basic syntax:

{ [argument] ':' [[fill] align] [sign] ['#'] [width [$]] ['.' precision [$]] [type] }
ElementMeaning
argumentNumber (0, 1, …), variable '21 or name,'18 e.g., print!("{x}").
fillThe character to fill empty spaces with (e.g., 0), if width is specified.
alignLeft (<), center (^), or right (>), if width is specified.
signCan be + for sign to always be printed.
#Alternate formatting, e.g., prettify DebugSTD formatter ? or prefix hex with 0x.
widthMinimum width (≥ 0), padding with fill (default to space). If starts with 0, zero-padded.
precisionDecimal digits (≥ 0) for numerics, or max width for non-numerics.
$Interpret width or precision as argument identifier instead to allow for dynamic formatting.
typeDebugSTD (?) formatting, hex (x), binary (b), octal (o), pointer (p), exp (e) … see more.
 
Format ExampleExplanation
{}Print the next argument using Display.STD
{x}Same, but use variable x from scope. '21
{:?}Print the next argument using Debug.STD
{2:#?}Pretty-print the 3rd argument with DebugSTD formatting.
{val:^2$}Center the val named argument, width specified by the 3rd argument.
{:<10.3}Left align with width 10 and a precision of 3.
{val:#x}Format val argument as hex, with a leading 0x (alternate format for x).
 
Full ExampleExplanation
println!("{}", x)Print x using DisplaySTD on std. out and append new line. '15 🗑️
println!("{x}")Same, but use variable x from scope. '21
format!("{a:.3} {b:?}")Convert a with 3 digits, add space, b with Debug STD, return String. '21
 

Tooling 工具化url

Project Anatomy 项目解剖url

Basic project layout, and common files and folders, as used by cargo.
基本项目布局,以及 cargo 使用的常见文件和文件夹。

Entry 条目Code 代码
📁 .cargo/Project-local cargo configuration, may contain config.toml. 🔗 🝖
项目本地的 cargo 配置,可能包含 config.toml . 🔗 🝖
📁 benches/Benchmarks for your crate, run via cargo bench, requires nightly by default. * 🚧
您的包的基准测试,通过 cargo bench 运行,默认情况下需要夜间版本。 * 🚧
📁 examples/Examples how to use your crate, they see your crate like external user would.
演示如何使用您的板条箱,他们会像外部用户一样看待您的板条箱。
          my_example.rsIndividual examples are run like cargo run --example my_example.
个体示例的运行方式如 cargo run --example my_example
📁 src/Actual source code for your project.
项目的实际源代码。
          main.rsDefault entry point for applications, this is what cargo run uses.
应用程序的默认入口点,这是 cargo run 使用的。
          lib.rsDefault entry point for libraries. This is where lookup for my_crate::f() starts.
库的默认入口点。这是查找 my_crate::f() 的起点。
📁 src/bin/Place for additional binaries, even in library projects.
额外二进制文件的存放位置,即使在库项目中也可以。
          extra.rsAdditional binary, run with cargo run --bin extra.
额外的二进制文件,使用 cargo run --bin extra 运行。
📁 tests/Integration tests go here, invoked via cargo test. Unit tests often stay in src/ file.
集成测试放在这里,通过 cargo test 调用。单元测试通常留在 src/ 文件中。
.rustfmt.tomlIn case you want to customize how cargo fmt works.
如果您想自定义 cargo fmt 的工作方式。
.clippy.tomlSpecial configuration for certain clippy lints, utilized via cargo clippy 🝖
特定 clippy lint 的特殊配置,通过 cargo clippy 🝖 利用
build.rsPre-build script, 🔗 useful when compiling C / FFI, …
预构建脚本, 🔗 在编译 C / FFI 时非常有用,..
Cargo.tomlMain project manifest, 🔗 Defines dependencies, artifacts …
主项目清单, 🔗 定义依赖项、构件..
Cargo.lockFor reproducible builds. Add to git for apps, consider not for libs. 💬 🔗 🔗
为了可重现的构建。将其添加到应用程序的 git 中,考虑不适用于库。 💬 🔗 🔗
rust-toolchain.tomlDefine toolchain override🔗 (channel, components, targets) for this project.
为该项目定义工具链覆盖 🔗 (通道,组件,目标)。

* On stable consider Criterion.
在稳定版本上考虑 Criterion。

 

Minimal examples for various entry points might look like:
各种入口点的最小示例可能如下所示:

// src/main.rs (default application entry point)

fn main() {
    println!("Hello, world!");
}
// src/lib.rs (default library entry point)

pub fn f() {}      // Is a public item in root, so it's accessible from the outside.

mod m {
    pub fn g() {}  // No public path (`m` not public) from root, so `g`
}                  // is not accessible from the outside of the crate.
// src/my_module.rs (any file of your project)

fn f() -> u32 { 0 }

#[cfg(test)]
mod test {
    use super::f;           // Need to import items from parent module. Has
                            // access to non-public members.
    #[test]
    fn ff() {
        assert_eq!(f(), 0);
    }
}
// tests/sample.rs (sample integration test)

#[test]
fn my_sample() {
    assert_eq!(my_crate::f(), 123); // Integration tests (and benchmarks) 'depend' to the crate like
}                                   // a 3rd party would. Hence, they only see public items.
// benches/sample.rs (sample benchmark)

#![feature(test)]   // #[bench] is still experimental

extern crate test;  // Even in '18 this is needed for … reasons.
                    // Normally you don't need this in '18 code.

use test::{black_box, Bencher};

#[bench]
fn my_algo(b: &mut Bencher) {
    b.iter(|| black_box(my_crate::f())); // `black_box` prevents `f` from being optimized away.
}
// build.rs (sample pre-build script)

fn main() {
    // You need to rely on env. vars for target; `#[cfg(…)]` are for host.
    let target_os = env::var("CARGO_CFG_TARGET_OS");
}

*See here for list of environment variables set.

// src/lib.rs (default entry point for proc macros)

extern crate proc_macro;  // Apparently needed to be imported like this.

use proc_macro::TokenStream;

#[proc_macro_attribute]   // Crates can now use `#[my_attribute]`
pub fn my_attribute(_attr: TokenStream, item: TokenStream) -> TokenStream {
    item
}
// Cargo.toml

[package]
name = "my_crate"
version = "0.1.0"

[lib]
proc-macro = true
 

Module trees and imports:
模块树和导入:

Modules BK EX REF and source files work as follows:
模块 BK EX REF 和源文件的工作方式如下:

  • Module tree needs to be explicitly defined, is not implicitly built from file system tree. 🔗
    模块树需要明确定义,而不是从文件系统树中隐式构建。 🔗
  • Module tree root equals library, app, … entry point (e.g., lib.rs).
    模块树根等于库、应用程序、...入口点(例如, lib.rs )。

Actual module definitions work as follows:
实际模块定义的工作方式如下:

  • A mod m {} defines module in-file, while mod m; will read m.rs or m/mod.rs.
    一个 mod m {} 在文件中定义模块,而 mod m; 将读取 m.rsm/mod.rs
  • Path of .rs based on nesting, e.g., mod a { mod b { mod c; }}} is either a/b/c.rs or a/b/c/mod.rs.
    基于嵌套的 .rs 路径,例如, mod a { mod b { mod c; }}} 要么是 a/b/c.rs ,要么是 a/b/c/mod.rs
  • Files not pathed from module tree root via some mod m; won't be touched by compiler! 🛑
    通过一些 mod m; 未经模块树根路径的文件不会被编译器处理! 🛑

Rust has three kinds of namespaces:

Namespace Types Namespace Functions Namespace Macros
mod X {} fn X() {} macro_rules! X { … }
X (crate) const X: u8 = 1;
trait X {} static X: u8 = 1;
enum X {}
union X {}
struct X {}
struct X;1
struct X();2

1 Counts in Types and in Functions, defines type X and constant X.
2 Counts in Types and in Functions, defines type X and function X.

  • In any given scope, for example within a module, only one item per namespace can exist, e.g.,
    • enum X {} and fn X() {} can coexist
    • struct X; and const X cannot coexist
  • With a use my_mod::X; all items called X will be imported.

Due to naming conventions (e.g., fn and mod are lowercase by convention) and common sense (most developers just don't name all things X) you won't have to worry about these kinds in most cases. They can, however, be a factor when designing macros.

 

Cargo 货物url

Commands and tools that are good to know.
命令和工具,值得了解。

Command 命令Description 描述
cargo initCreate a new project for the latest edition.
为最新版本创建一个新项目。
cargo buildBuild the project in debug mode (--release for all optimization).
在调试模式下构建项目( --release 以进行所有优化)。
cargo checkCheck if project would compile (much faster).
检查项目是否能够编译(速度更快)。
cargo testRun tests for the project.
运行项目的测试。
cargo doc --openLocally generate documentation for your code and dependencies.
本地生成代码和依赖项的文档。
cargo runRun your project, if a binary is produced (main.rs).
运行您的项目,如果生成了二进制文件(main.rs)。
     cargo run --bin bRun binary b. Unifies feat. with other dependents (can be confusing).
运行二进制 b 。将功能与其他依赖项统一(可能会令人困惑)。
     cargo run --package wRun main of sub-worksp. w. Treats features more sanely.
运行子工作区的主要部分。 w 。更明智地处理功能。
cargo … --timingsShow what crates caused your build to take so long. 🔥
显示导致构建时间过长的箱子。 🔥
cargo treeShow dependency graph. 显示依赖关系图。
cargo +{nightly, stable} …Use given toolchain for command, e.g., for 'nightly only' tools.
使用给定的工具链进行命令,例如,对于“仅夜间”工具。
cargo +nightly …Some nightly-only commands (substitute with command below)
一些仅限夜间使用的命令(将 替换为下面的命令)
     rustc -- -Zunpretty=expandedShow expanded macros. 🚧
显示扩展的宏。 🚧
rustup docOpen offline Rust documentation (incl. the books), good on a plane!
打开离线 Rust 文档(包括书籍),在飞机上很方便!

Here cargo build means you can either type cargo build or just cargo b; and --release means it can be replaced with -r.
这里的 cargo build 表示您可以输入 cargo build 或者只需 cargo b ;而 --release 表示它可以被 -r 替换。

 

These are optional rustup components. Install them with rustup component add [tool].
这些是可选的 rustup 组件。使用 rustup component add [tool] 安装它们。

Tool 工具Description 描述
cargo clippyAdditional (lints) catching common API misuses and unidiomatic code. 🔗
额外(lints)捕捉常见的 API 误用和不符合惯例的代码。 🔗
cargo fmtAutomatic code formatter (rustup component add rustfmt). 🔗
自动代码格式化程序( rustup component add rustfmt )。 🔗
 

A large number of additional cargo plugins can be found here.
这里可以找到大量额外的货物插件。

 

Cross Compilation 交叉编译url

🔘 Check target is supported.
🔘 检查目标是否受支持。

🔘 Install target via rustup target install aarch64-linux-android (for example).
🔘 通过 rustup target install aarch64-linux-android 安装目标(例如)。

🔘 Install native toolchain (required to link, depends on target).
🔘 安装本地工具链(用于链接,取决于目标)。

Get from target vendor (Google, Apple, …), might not be available on all hosts (e.g., no iOS toolchain on Windows).
从目标供应商(Google、Apple 等)获取,可能不适用于所有主机(例如,在 Windows 上没有 iOS 工具链)。

Some toolchains require additional build steps (e.g., Android's make-standalone-toolchain.sh).
某些工具链需要额外的构建步骤(例如,Android 的 make-standalone-toolchain.sh )。

🔘 Update ~/.cargo/config.toml like this:
🔘 像这样更新 ~/.cargo/config.toml

[target.aarch64-linux-android]
linker = "[PATH_TO_TOOLCHAIN]/aarch64-linux-android/bin/aarch64-linux-android-clang"

or 

[target.aarch64-linux-android]
linker = "C:/[PATH_TO_TOOLCHAIN]/prebuilt/windows-x86_64/bin/aarch64-linux-android21-clang.cmd"

🔘 Set environment variables (optional, wait until compiler complains before setting):
🔘 设置环境变量(可选,在编译器发出警告之前等待设置):

set CC=C:\[PATH_TO_TOOLCHAIN]\prebuilt\windows-x86_64\bin\aarch64-linux-android21-clang.cmd
set CXX=C:\[PATH_TO_TOOLCHAIN]\prebuilt\windows-x86_64\bin\aarch64-linux-android21-clang.cmd
set AR=C:\[PATH_TO_TOOLCHAIN]\prebuilt\windows-x86_64\bin\aarch64-linux-android-ar.exe
…

Whether you set them depends on how compiler complains, not necessarily all are needed.
无论您设置它们取决于编译器的投诉方式,不一定所有都是必需的。

Some platforms / configurations can be extremely sensitive how paths are specified (e.g., \ vs /) and quoted.
某些平台/配置可能对指定路径的方式非常敏感(例如, \ vs / )并带引号。

✔️ Compile with cargo build --target=aarch64-linux-android ✔️ 使用 cargo build --target=aarch64-linux-android 编译

 

Tooling Directives 工具指令url

Special tokens embedded in source code used by tooling or preprocessing.
源代码中嵌入的特殊标记,用于工具或预处理。

Inside a declarative BK macro by example BK EX REF macro_rules! implementation these fragment specifiers REF work:
在一个声明性 BK 宏中,通过示例 BK EX REF macro_rules! 实现这些片段指示符 REF 起作用:

Within Macros 在宏内Explanation 解释
$x:tyMacro capture (here a $x is the capture and ty means x must be type).
宏捕获(这里 $x 是捕获, ty 表示 x 必须是类型)。
     $x:blockA block {} of statements or expressions, e.g., { let x = 5; }
一个 {} 的语句或表达式块,例如, { let x = 5; }
     $x:exprAn expression, e.g., x, 1 + 1, String::new() or vec![]
一个表达式,例如, x1 + 1String::new()vec![]
     $x:identAn identifier, for example in let x = 0; the identifier is x.
let x = 0; 中,例如标识符为 x
     $x:itemAn item, like a function, struct, module, etc.
项目,如函数、结构、模块等。
     $x:lifetimeA lifetime (e.g., 'a, 'static, etc.).
终身(例如, 'a'static 等)。
     $x:literalA literal (e.g., 3, "foo", b"bar", etc.).
一个文字(例如, 3"foo"b"bar" 等)。
     $x:metaA meta item; the things that go inside #[…] and #![…] attributes.
一个元项目;放在 #[…]#![…] 属性中的内容。
     $x:patA pattern, e.g., Some(t), (17, 'a') or _.
一个模式,例如, Some(t)(17, 'a')_
     $x:pathA path (e.g., foo, ::std::mem::replace, transmute::<_, int>).
路径(例如, foo::std::mem::replacetransmute::<_, int> )。
     $x:stmtA statement, e.g., let x = 1 + 1;, String::new(); or vec![];
一个语句,例如, let x = 1 + 1;String::new();vec![];
     $x:ttA single token tree, see here for more details.
单令牌树,请参阅此处了解更多详情。
     $x:tyA type, e.g., String, usize or Vec<u8>.
一种类型,例如 StringusizeVec<u8>
     $x:visA visibility modifier; pub, pub(crate), etc.
可见性修饰符; pubpub(crate) 等。
$crateSpecial hygiene variable, crate where macros is defined. ?
特殊的卫生变量,创建宏定义的箱子。 ?

Inside a doc comment BK EX REF these work:

Within Doc CommentsExplanation
```…```Include a doc test (doc code running on cargo test).
```X,Y …```Same, and include optional configurations; with X, Y being …
     rustMake it explicit test is written in Rust; implied by Rust tooling.
     -Compile test. Run test. Fail if panic. Default behavior.
     should_panicCompile test. Run test. Execution should panic. If not, fail test.
     no_runCompile test. Fail test if code can't be compiled, Don't run test.
     compile_failCompile test but fail test if code can be compiled.
     ignoreDo not compile. Do not run. Prefer option above instead.
     edition2018Execute code as Rust '18; default is '15.
#Hide line from documentation (``` # use x::hidden; ```).
[`S`]Create a link to struct, enum, trait, function, … S.
[`S`](crate::S)Paths can also be used, in the form of markdown links.

Attributes affecting the whole crate or app:

Opt-Out'sOnExplanation
#![no_std]CDon't (automatically) import stdSTD ; use coreSTD instead. REF
#![no_implicit_prelude]CMDon't add preludeSTD, need to manually import None, Vec, … REF
#![no_main]CDon't emit main() in apps if you do that yourself. REF
 
Opt-In'sOnExplanation
#![feature(a, b, c)]CRely on f. that may not get stabilized, c. Unstable Book. 🚧
 
BuildsOnExplanation
#![crate_name = "x"]CSpecify current crate name, e.g., when not using cargo. ? REF 🝖
#![crate_type = "bin"]CSpecify current crate type (bin, lib, dylib, cdylib, …). REF 🝖
#![recursion_limit = "123"]CSet compile-time recursion limit for deref, macros, … REF 🝖
#![type_length_limit = "456"]CLimits maximum number of type substitutions. REF 🝖
#![windows_subsystem = "x"]COn Windows, make a console or windows app. REF 🝖
 
HandlersOnExplanation
#[alloc_error_handler]FMake some fn(Layout) -> ! the allocation fail. handler. 🔗 🚧
#[global_allocator]SMake static item impl. GlobalAlloc STD global allocator. REF
#[panic_handler]FMake some fn(&PanicInfo) -> ! app's panic handler. REF

Attributes primarily governing emitted code:

Developer UXOnExplanation
#[non_exhaustive]TFuture-proof struct or enum; hint it may grow in future. REF
#[path = "x.rs"]MGet module from non-standard file. REF
#[diagnostic::on_unimplemented]XGive better error messages when trait not implemented. RFC
 
CodegenOnExplanation
#[cold]FHint that function probably isn't going to be called. REF
#[inline]FNicely suggest compiler should inline function at call sites. REF
#[inline(always)]FEmphatically threaten compiler to inline call, or else. REF
#[inline(never)]FInstruct compiler to feel sad if it still inlines the function. REF
#[repr(X)]1TUse another representation instead of the default rust REF one:
#[target_feature(enable="x")]FEnable CPU feature (e.g., avx2) for code of unsafe fn. REF
#[track_caller]FAllows fn to find callerSTD for better panic messages. REF
     #[repr(C)]TUse a C-compatible (f. FFI), predictable (f. transmute) layout. REF
     #[repr(C, u8)]enumGive enum discriminant the specified type. REF
     #[repr(transparent)]TGive single-element type same layout as contained field. REF
     #[repr(packed(1))]TLower align. of struct and contained fields, mildly UB prone. REF
     #[repr(align(8))]TRaise alignment of struct to given value, e.g., for SIMD types. REF

1 Some representation modifiers can be combined, e.g., #[repr(C, packed(1))].

 
LinkingOnExplanation
#[export_name = "foo"]FSExport a fn or static under a different name. REF
#[link(name="x", kind="y")]XNative lib to link against when looking up symbol. REF
#[link_name = "foo"]FName of symbol to search for resolving extern fn. REF
#[link_section = ".sample"]FSSection name of object file where item should be placed. REF
#[no_mangle]*Use item name directly as symbol name, instead of mangling. REF
#[no_link]XDon't link extern crate when only wanting macros. REF
#[used]SDon't optimize away static variable despite it looking unused. REF

Attributes used by Rust tools to improve code quality:

Code PatternsOnExplanation
#[allow(X)]*Instruct rustc / clippy to ign. class X of possible issues. REF
#[warn(X)] 1*… emit a warning, mixes well with clippy lints. 🔥 REF
#[deny(X)] 1*… fail compilation. REF
#[forbid(X)] 1*… fail compilation and prevent subsequent allow overrides. REF
#[deprecated = "msg"]*Let your users know you made a design mistake. REF
#[must_use = "msg"]FTXMakes compiler check return value is processed by caller. 🔥 REF

1 💬 There is some debate which one is the best to ensure high quality crates. Actively maintained multi-dev crates probably benefit from more aggressive deny or forbid lints; less-regularly updated ones probably more from conservative use of warn (as future compiler or clippy updates may suddenly break otherwise working code with minor issues).

 
TestsOnExplanation
#[test]FMarks the function as a test, run with cargo test. 🔥 REF
#[ignore = "msg"]FCompiles but does not execute some #[test] for now. REF
#[should_panic]FTest must panic!() to actually succeed. REF
#[bench]FMark function in bench/ as benchmark for cargo bench. 🚧 REF
 
FormattingOnExplanation
#[rustfmt::skip]*Prevent cargo fmt from cleaning up item. 🔗
#![rustfmt::skip::macros(x)]CM… from cleaning up macro x. 🔗
#![rustfmt::skip::attributes(x)]CM… from cleaning up attribute x. 🔗
 
DocumentationOnExplanation
#[doc = "Explanation"]*Same as adding a /// doc comment. 🔗
#[doc(alias = "other")]*Provide other name for search in docs. 🔗
#[doc(hidden)]*Prevent item from showing up in docs. 🔗
#![doc(html_favicon_url = "")]CSets the favicon for the docs. 🔗
#![doc(html_logo_url = "")]CThe logo used in the docs. 🔗
#![doc(html_playground_url = "")]CGenerates Run buttons and uses given service. 🔗
#![doc(html_root_url = "")]CBase URL for links to external crates. 🔗
#![doc(html_no_source)]CPrevents source from being included in docs. 🔗

Attributes related to the creation and use of macros:

Macros By ExampleOnExplanation
#[macro_export]!Export macro_rules! as pub on crate level REF
#[macro_use]MXLet macros persist past mod.; or import from extern crate. REF
 
Proc MacrosOnExplanation
#[proc_macro]FMark fn as function-like procedural m. callable as m!(). REF
#[proc_macro_derive(Foo)]FMark fn as derive macro which can #[derive(Foo)]. REF
#[proc_macro_attribute]FMark fn as attribute macro for new #[x]. REF
 
DerivesOnExplanation
#[derive(X)]TLet some proc macro provide a goodish impl of trait X. 🔥 REF

Attributes governing conditional compilation:

Config AttributesOnExplanation
#[cfg(X)]*Include item if configuration X holds. REF
#[cfg(all(X, Y, Z))]*Include item if all options hold. REF
#[cfg(any(X, Y, Z))]*Include item if at least one option holds. REF
#[cfg(not(X))]*Include item if X does not hold. REF
#[cfg_attr(X, foo = "msg")]*Apply #[foo = "msg"] if configuration X holds. REF
 

⚠️ Note, options can generally be set multiple times, i.e., the same key can show up with multiple values. One can expect #[cfg(target_feature = "avx")] and #[cfg(target_feature = "avx2")] to be true at the same time.

 
Known OptionsOnExplanation
#[cfg(debug_assertions)]*Whether debug_assert!() & co. would panic. REF
#[cfg(feature = "foo")]*When your crate was compiled with f. foo. 🔥 REF
#[cfg(target_arch = "x86_64")]*The CPU architecture crate is compiled for. REF
#[cfg(target_env = "msvc")]*How DLLs and functions are interf. with on OS. REF
#[cfg(target_endian = "little")]*Main reason your new zero-cost prot. fails. REF
#[cfg(target_family = "unix")]*Family operating system belongs to. REF
#[cfg(target_feature = "avx")]*Whether a particular class of instructions is avail. REF
#[cfg(target_os = "macos")]*Operating system your code will run on. REF
#[cfg(target_pointer_width = "64")]*How many bits ptrs, usize and words have. REF
#[cfg(target_vendor = "apple")]*Manufacturer of target. REF
#[cfg(panic = "unwind")]*Whether unwind or abort will happen on panic. ?
#[cfg(proc_macro)]*Whether crate compiled as proc macro. REF
#[cfg(test)]*Whether compiled with cargo test. 🔥 REF

Environment variables and outputs related to the pre-build script.

Input EnvironmentExplanation 🔗
CARGO_FEATURE_XEnvironment variable set for each feature x activated.
     CARGO_FEATURE_SOMETHINGIf feature something were enabled.
     CARGO_FEATURE_SOME_FEATUREIf f. some-feature were enabled; dash - converted to _.
CARGO_CFG_XExposes cfg's; joins mult. opts. by , and converts - to _.
     CARGO_CFG_TARGET_OS=macosIf target_os were set to macos.
     CARGO_CFG_TARGET_FEATURE=avx,avx2If target_feature were set to avx and avx2.
OUT_DIRWhere output should be placed.
TARGETTarget triple being compiled for.
HOSTHost triple (running this build script).
PROFILECan be debug or release.

Available in build.rs via env::var()?. List not exhaustive.

 
Output StringExplanation 🔗
cargo:rerun-if-changed=PATH(Only) run this build.rs again if PATH changed.
cargo:rerun-if-env-changed=VAR(Only) run this build.rs again if environment VAR changed.
cargo:rustc-cfg=KEY[="VALUE"]Emit given cfg option to be used for later compilation.
cargo:rustc-cdylib-link-arg=FLAG When building a cdylib, pass linker flag.
cargo:rustc-env=VAR=VALUE Emit var accessible via env!() in crate during compilation.
cargo:rustc-flags=FLAGSAdd special flags to compiler. ?
cargo:rustc-link-lib=[KIND=]NAMELink native library as if via -l option.
cargo:rustc-link-search=[KIND=]PATHSearch path for native library as if via -L option.
cargo:warning=MESSAGEEmit compiler warning.

Emitted from build.rs via println!(). List not exhaustive.

For the On column in attributes:
对于属性中的 On 列:

C means on crate level (usually given as #![my_attr] in the top level file).
C 表示在板条级别(通常在顶层文件中给出为 #![my_attr] )。

M means on modules.
M 表示在模块上。

F means on functions.
F 表示在函数上。

S means on static.
S 表示静态。

T means on types.
T 表示在类型上。

X means something special.
X 代表着特殊含义。

! means on macros.
! 表示宏。

* means on almost any item.
* 表示几乎任何项目。


Working with Types 处理类型url

Types, Traits, Generics 类型,特征,泛型url

Allowing users to bring their own types and avoid code duplication.
允许用户使用自己的类型,避免代码重复。

Types
u8 String Device
  • Set of values with given semantics, layout, …
TypeValues
u8{ 0u8, 1u8, …, 255u8 }
char{ 'a', 'b', … '🦀' }
struct S(u8, char){ (0u8, 'a'), … (255u8, '🦀') }

Sample types and sample values.

Type Equivalence and Conversions
类型等价性和转换
u8 &u8 &mut u8 [u8; 1] String
  • It may be obvious but   u8,    &u8,    &mut u8, are entirely different from each other
  • Any t: T only accepts values from exactly T, e.g.,
    • f(0_u8) can't be called with f(&0_u8),
    • f(&mut my_u8) can't be called with f(&my_u8),
    • f(0_u8) can't be called with f(0_i8).

Yes, 0 != 0 (in a mathematical sense) when it comes to types! In a language sense, the operation ==(0u8, 0u16) just isn't defined to prevent happy little accidents.

TypeValues
u8{ 0u8, 1u8, …, 255u8 }
u16{ 0u16, 1u16, …, 65_535u16 }
&u8{ 0xffaa&u8, 0xffbb&u8, … }
&mut u8{ 0xffaa&mut u8, 0xffbb&mut u8, … }

How values differ between types.

  • However, Rust might sometimes help to convert between types1
    • casts manually convert values of types, 0_i8 as u8
    • coercions automatically convert types if safe2, let x: &u8 = &mut 0_u8;

1 Casts and coercions convert values from one set (e.g., u8) to another (e.g., u16), possibly adding CPU instructions to do so; and in such differ from subtyping, which would imply type and subtype are part of the same set (e.g., u8 being subtype of u16 and 0_u8 being the same as 0_u16) where such a conversion would be purely a compile time check. Rust does not use subtyping for regular types (and 0_u8 does differ from 0_u16) but sort-of for lifetimes. 🔗

2 Safety here is not just physical concept (e.g., &u8 can't be coerced to &u128), but also whether 'history has shown that such a conversion would lead to programming errors'.

Implementations — impl S { } 实现 — impl S { }
u8 impl { … } String impl { … } Port impl { … }
impl Port {
    fn f() { … }
}
  • Types usually come with inherent implementations, REF e.g., impl Port {}, behavior related to type:
    • associated functions Port::new(80)
    • methods port.close()

What's considered related is more philosophical than technical, nothing (except good taste) would prevent a u8::play_sound() from happening.

Traits — trait T { } 特征 — trait T { }
Copy Clone Sized ShowHex
  • Traits
    • are way to "abstract" behavior,
    • trait author declares semantically this trait means X,
    • other can implement ("subscribe to") that behavior for their type.
  • Think about trait as "membership list" for types:
Copy Trait
Self
u8
u16
Clone Trait
Self
u8
String
Sized Trait
Self
char
Port

Traits as membership tables, Self refers to the type included.

  • Whoever is part of that membership list will adhere to behavior of list.
  • Traits can also include associated methods, functions, …
trait ShowHex {
    // Must be implemented according to documentation.
    fn as_hex() -> String;

    // Provided by trait author.
    fn print_hex() {}
}
Copy
trait Copy { }
  • Traits without methods often called marker traits.
  • Copy is example marker trait, meaning memory may be copied bitwise.
Sized
  • Some traits entirely outside explicit control
  • Sized provided by compiler for types with known size; either this is, or isn't
Implementing Traits for Types — impl T for S { }
为类型实现特性 — impl T for S { }
impl ShowHex for Port { … }
  • Traits are implemented for types 'at some point'.
  • Implementation impl A for B add type B to the trait membership list:
ShowHex Trait
Self
Port
  • Visually, you can think of the type getting a "badge" for its membership:
u8 impl { … } Sized Clone Copy Device impl { … } Transport Port impl { … } Sized Clone ShowHex
Traits vs. Interfaces 特征 vs. 接口
👩‍🦰 Eat 🧔 Venison Eat 🎅 venison.eat()
 

Interfaces

  • In Java, Alice creates interface Eat.
  • When Bob authors Venison, he must decide if Venison implements Eat or not.
  • In other words, all membership must be exhaustively declared during type definition.
  • When using Venison, Santa can make use of behavior provided by Eat:
// Santa imports `Venison` to create it, can `eat()` if he wants.
import food.Venison;

new Venison("rudolph").eat();

 
 

👩‍🦰 Eat 🧔 Venison 👩‍🦰 / 🧔 Venison + Eat 🎅 venison.eat()
 

Traits

  • In Rust, Alice creates trait Eat.
  • Bob creates type Venison and decides not to implement Eat (he might not even know about Eat).
  • Someone* later decides adding Eat to Venison would be a really good idea.
  • When using Venison Santa must import Eat separately:
// Santa needs to import `Venison` to create it, and import `Eat` for trait method.
use food::Venison;
use tasks::Eat;

// Ho ho ho
Venison::new("rudolph").eat();

* To prevent two persons from implementing Eat differently Rust limits that choice to either Alice or Bob; that is, an impl Eat for Venison may only happen in the crate of Venison or in the crate of Eat. For details see coherence. ?

Type Constructors — Vec<>
Vec<u8> Vec<char>
  • Vec<u8> is type "vector of bytes"; Vec<char> is type "vector of chars", but what is Vec<>?
ConstructValues
Vec<u8>{ [], [1], [1, 2, 3], … }
Vec<char>{ [], ['a'], ['x', 'y', 'z'], … }
Vec<>-

Types vs type constructors.

Vec<>
  • Vec<> is no type, does not occupy memory, can't even be translated to code.
  • Vec<> is type constructor, a "template" or "recipe to create types"
    • allows 3rd party to construct concrete type via parameter,
    • only then would this Vec<UserType> become real type itself.
Generic Parameters — <T>
Vec<T> [T; 128] &T &mut T S<T>
  • Parameter for Vec<> often named T therefore Vec<T>.
  • T "variable name for type" for user to plug in something specific, Vec<f32>, S<u8>, …
Type ConstructorProduces Family
struct Vec<T> {}Vec<u8>, Vec<f32>, Vec<Vec<u8>>, …
[T; 128][u8; 128], [char; 128], [Port; 128]
&T&u8, &u16, &str, …

Type vs type constructors.

// S<> is type constructor with parameter T; user can supply any concrete type for T.
struct S<T> {
    x: T
}

// Within 'concrete' code an existing type must be given for T.
fn f() {
    let x: S<f32> = S::new(0_f32);
}

Const Generics — [T; N] and S<const N: usize>
[T; n] S<const N>
  • Some type constructors not only accept specific type, but also specific constant.
  • [T; n] constructs array type holding T type n times.
  • For custom types declared as MyArray<T, const N: usize>.
Type ConstructorProduces Family
[u8; N][u8; 0], [u8; 1], [u8; 2], …
struct S<const N: usize> {}S<1>, S<6>, S<123>, …

Type constructors based on constant.

let x: [u8; 4]; // "array of 4 bytes"
let y: [f32; 16]; // "array of 16 floats"

// `MyArray` is type constructor requiring concrete type `T` and
// concrete usize `N` to construct specific type.
struct MyArray<T, const N: usize> {
    data: [T; N],
}
Bounds (Simple) — where T: X
🧔 Num<T> 🎅 Num<u8> Num<f32> Num<Cmplx>   u8 Absolute Dim Mul Port Clone ShowHex
  • If T can be any type, how can we reason about (write code) for such a Num<T>?
  • Parameter bounds:
    • limit what types (trait bound) or values (const bound ?) allowed,
    • we now can make use of these limits!
  • Trait bounds act as "membership check":
// Type can only be constructed for some `T` if that
// T is part of `Absolute` membership list.
struct Num<T> where T: Absolute {
    …
}

Absolute Trait
Self
u8
u16

We add bounds to the struct here. In practice it's nicer add bounds to the respective impl blocks instead, see later this section.

Bounds (Compound) — where T: X + Y
u8 Absolute Dim Mul f32 Absolute Mul char Cmplx Absolute Dim Mul DirName TwoD Car DirName
struct S<T>
where
    T: Absolute + Dim + Mul + DirName + TwoD
{ … }
  • Long trait bounds can look intimidating.
  • In practice, each + X addition to a bound merely cuts down space of eligible types.
Implementing Families — impl<>
 

When we write:

impl<T> S<T> where T: Absolute + Dim + Mul {
    fn f(&self, x: T) { … };
}

It can be read as:

  • here is an implementation recipe for any type T (the impl <T> part),
  • where that type must be member of the Absolute + Dim + Mul traits,
  • you may add an implementation block to the type family S<>,
  • containing the methods …

You can think of such impl<T> … {} code as abstractly implementing a family of behaviors. REF Most notably, they allow 3rd parties to transparently materialize implementations similarly to how type constructors materialize types:

// If compiler encounters this, it will
// - check `0` and `x` fulfill the membership requirements of `T`
// - create two new version of `f`, one for `char`, another one for `u32`.
// - based on "family implementation" provided
s.f(0_u32);
s.f('x');
Blanket Implementations — impl<T> X for T { … }
 

Can also write "family implementations" so they apply trait to many types:

// Also implements Serialize for any type if that type already implements ToHex
impl<T> Serialize for T where T: ToHex { … }

These are called blanket implementations.

ToHex
Self
Port
Device

→ Whatever was in left table, may be added to right table, based on the following recipe (impl) →

Serialize Trait
Self
u8
Port

They can be neat way to give foreign types functionality in a modular way if they just implement another interface.

Trait Parameters — Trait<In> { type Out; }
 

Notice how some traits can be "attached" multiple times, but others just once?

Port From<u8> From<u16> Port Deref type u8;
 

Why is that?

  • Traits themselves can be generic over two kinds of parameters:
    • trait From<I> {}
    • trait Deref { type O; }
  • Remember we said traits are "membership lists" for types and called the list Self?
  • Turns out, parameters I (for input) and O (for output) are just more columns to that trait's list:
impl From<u8> for u16 {}
impl From<u16> for u32 {}
impl Deref for Port { type O = u8; }
impl Deref for String { type O = str; }
From
SelfI
u16u8
u32u16
Deref
SelfO
Portu8
Stringstr

Input and output parameters.

Now here's the twist,

  • any output O parameters must be uniquely determined by input parameters I,
  • (in the same way as a relation X Y would represent a function),
  • Self counts as an input.

A more complex example:

trait Complex<I1, I2> {
    type O1;
    type O2;
}
  • this creates a relation of types named Complex,
  • with 3 inputs (Self is always one) and 2 outputs, and it holds (Self, I1, I2) => (O1, O2)
Complex
Self [I]I1I2O1O2
Playeru8charf32f32
EvilMonsteru16stru8u8
EvilMonsteru16Stringu8u8
NiceMonsteru16Stringu8u8
NiceMonster🛑u16Stringu8u16

Various trait implementations. The last one is not valid as (NiceMonster, u16, String) has
already uniquely determined the outputs.

Trait Authoring Considerations (Abstract)
👩‍🦰 A<I> 🧔 Car 👩‍🦰 / 🧔 Car A<I> 🎅 car.a(0_u8) car.a(0_f32)
👩‍🦰 B type O; 🧔 Car 👩‍🦰 / 🧔 Car B T = u8; 🎅 car.b(0_u8) car.b(0_f32)
  • Parameter choice (input vs. output) also determines who may be allowed to add members:
    • I parameters allow "familes of implementations" be forwarded to user (Santa),
    • O parameters must be determined by trait implementor (Alice or Bob).
trait A<I> { }
trait B { type O; }

// Implementor adds (X, u32) to A.
impl A<u32> for X { }

// Implementor adds family impl. (X, …) to A, user can materialze.
impl<T> A<T> for Y { }

// Implementor must decide specific entry (X, O) added to B.
impl B for X { type O = u32; }
A
SelfI
Xu32
Y

Santa may add more members by providing his own type for T.

B
SelfO
PlayerString
Xu32

For given set of inputs (here Self), implementor must pre-select O.

Trait Authoring Considerations (Example)
Query vs. Query<I> vs. Query type O; vs. Query<I> type O;
 

Choice of parameters goes along with purpose trait has to fill.


No Additional Parameters

trait Query {
    fn search(&self, needle: &str);
}

impl Query for PostgreSQL { … }
impl Query for Sled { … }

postgres.search("SELECT …");
👩‍🦰 Query 🧔 PostgreSQL Query Sled Query
 

Trait author assumes:

  • neither implementor nor user need to customize API.
 

Input Parameters

trait Query<I> {
    fn search(&self, needle: I);
}

impl Query<&str> for PostgreSQL { … }
impl Query<String> for PostgreSQL { … }
impl<T> Query<T> for Sled where T: ToU8Slice { … }

postgres.search("SELECT …");
postgres.search(input.to_string());
sled.search(file);
👩‍🦰 Query<I> 🧔 PostgreSQL Query<&str> Query<String> Sled Query<T> where T is ToU8Slice.
 

Trait author assumes:

  • implementor would customize API in multiple ways for same Self type,
  • users may want ability to decide for which I-types behavior should be possible.
 

Output Parameters

trait Query {
    type O;
    fn search(&self, needle: Self::O);
}

impl Query for PostgreSQL { type O = String; …}
impl Query for Sled { type O = Vec<u8>; … }

postgres.search("SELECT …".to_string());
sled.search(vec![0, 1, 2, 4]);
👩‍🦰 Query type O; 🧔 PostgreSQL Query O = String; Sled Query O = Vec<u8>;
 

Trait author assumes:

  • implementor would customize API for Self type (but in only one way),
  • users do not need, or should not have, ability to influence customization for specific Self.

As you can see here, the term input or output does not (necessarily) have anything to do with whether I or O are inputs or outputs to an actual function!

 

Multiple In- and Output Parameters

trait Query<I> {
    type O;
    fn search(&self, needle: I) -> Self::O;
}

impl Query<&str> for PostgreSQL { type O = String; … }
impl Query<CString> for PostgreSQL { type O = CString; … }
impl<T> Query<T> for Sled where T: ToU8Slice { type O = Vec<u8>; … }

postgres.search("SELECT …").to_uppercase();
sled.search(&[1, 2, 3, 4]).pop();
👩‍🦰 Query<I> type O; 🧔 PostgreSQL Query<&str> O = String; Query<CString> O = CString; Sled Query<T> O = Vec<u8>; where T is ToU8Slice.
 

Like examples above, in particular trait author assumes:

  • users may want ability to decide for which I-types ability should be possible,
  • for given inputs, implementor should determine resulting output type.
Dynamic / Zero Sized Types
MostTypes Sized Normal types. vs. Z Sized Zero sized. vs. str Sized Dynamically sized. [u8] Sized dyn Trait Sized Sized
  • A type T is Sized STD if at compile time it is known how many bytes it occupies, u8 and &[u8] are, [u8] isn't.
  • Being Sized means impl Sized for T {} holds. Happens automatically and cannot be user impl'ed.
  • Types not Sized are called dynamically sized types BK NOM REF (DSTs), sometimes unsized.
  • Types without data are called zero sized types NOM (ZSTs), do not occupy space.
ExampleExplanation
struct A { x: u8 }Type A is sized, i.e., impl Sized for A holds, this is a 'regular' type.
struct B { x: [u8] }Since [u8] is a DST, B in turn becomes DST, i.e., does not impl Sized.
struct C<T> { x: T }Type params have implicit T: Sized bound, e.g., C<A> is valid, C<B> is not.
struct D<T: ?Sized> { x: T }Using ?Sized REF allows opt-out of that bound, i.e., D<B> is also valid.
struct E;Type E is zero-sized (and also sized) and will not consume memory.
trait F { fn f(&self); }Traits do not have an implicit Sized bound, i.e., impl F for B {} is valid.
     trait F: Sized {}Traits can however opt into Sized via supertraits.
trait G { fn g(self); }For Self-like params DST impl may still fail as params can't go on stack.
?Sized
S<T> S<u8> S<char> S<str>
struct S<T> { … }
  • T can be any concrete type.
  • However, there exists invisible default bound T: Sized, so S<str> is not possible out of box.
  • Instead we have to add T : ?Sized to opt-out of that bound:
S<T> S<u8> S<char> S<str>
struct S<T> where T: ?Sized { … }
Generics and Lifetimes — <'a>
S<'a> &'a f32 &'a mut u8
  • Lifetimes act* as type parameters:
    • user must provide specific 'a to instantiate type (compiler will help within methods),
    • S<'p> and S<'q> are different types, just like Vec<f32> and Vec<u8> are
    • meaning you can't just assign value of type S<'a> to variable expecting S<'b> (exception: subtype relationship for lifetimes, i.e., 'a outlives 'b).
S<'a> S<'auto> S<'static>
  • 'static is only globally available type of the lifetimes kind.
// `'a is free parameter here (user can pass any specific lifetime)
struct S<'a> {
    x: &'a u32
}

// In non-generic code, 'static is the only nameable lifetime we can explicitly put in here.
let a: S<'static>;

// Alternatively, in non-generic code we can (often must) omit 'a and have Rust determine
// the right value for 'a automatically.
let b: S;

* There are subtle differences, for example you can create an explicit instance 0 of a type u32, but with the exception of 'static you can't really create a lifetime, e.g., "lines 80 - 100", the compiler will do that for you. 🔗

Examples expand by clicking.
示例展开点击。

Foreign Types and Traits 外部类型和特质url

A visual overview of types and traits in your crate and upstream.
您的箱和上游中类型和特征的视觉概述。

u8 u16 f32 bool char File String Builder Vec<T> Vec<T> Vec<T> &'a T &'a T &'a T &mut 'a T &mut 'a T &mut 'a T [T; n] [T; n] [T; n] Vec<T> Vec<T> f<T>() {} drop() {} PI dbg! Copy Deref type Tgt; From<T> From<T> From<T> Items defined in upstream crates.
在上游板块中定义的项目。
Serialize Transport ShowHex Device From<u8> Foreign trait impl. for local type.
本地类型的外部特质实现。
String Serialize Local trait impl. for foreign type.
外部类型的本地特质实现。
String From<u8> 🛑 Illegal, foreign trait for f. type.
🛑 非法,f. 类型的外部 trait。
String From<Port> Exception: Legal if used type local.
异常:如果使用本地类型,则合法。
Port From<u8> From<u16> Mult. impl. of trait with differing IN params.
具有不同输入参数的 trait 的多个实现。
Container Deref Tgt = u8; Deref Tgt = f32; 🛑 Illegal impl. of trait with differing OUT params.
🛑 实现了具有不同 OUT 参数的 trait。
T T T ShowHex Blanket impl. of trait for any type.
任何类型的特质的覆盖实现。
Your crate. 您的板条箱。

Examples of traits and types, and which traits you can implement for which type.
特征和类型的示例,以及您可以为哪种类型实现哪些特征。

Type Conversions 类型转换url

How to get B when you have A?
当你有 A 时如何获得 B

fn f(x: A) -> B {
    // How can you obtain B from A?
}
Method 方法Explanation 解释
Identity 身份Trivial case, B is exactly A.
平凡情况, B 正好是 A
Computation 计算Create and manipulate instance of B by writing code transforming data.
通过编写代码转换数据来创建和操作 B 的实例。
Casts 转型On-demand conversion between types where caution is advised.
需要谨慎的情况下,按需在类型之间进行转换。
Coercions 强制转换Automatic conversion within 'weakening ruleset'.1
'减弱规则集'内的自动转换。 1
Subtyping 子类型化Automatic conversion within 'same-layout-different-lifetimes ruleset'.1
'same-layout-different-lifetimes ruleset' 内的自动转换。 1
 

1 While both convert A to B, coercions generally link to an unrelated B (a type "one could reasonably expect to have different methods"), while subtyping links to a B differing only in lifetimes.
1 尽管都将 A 转换为 B ,强制转换通常链接到一个不相关的 B (一个“人们可以合理期望具有不同方法”的类型),而子类型链接到一个仅在生命周期上有所不同的 B

fn f(x: A) -> B {
    x.into()
}

Bread and butter way to get B from A. Some traits provide canonical, user-computable type relations:

TraitExampleTrait implies …
impl From<A> for B {}a.into()Obvious, always-valid relation.
impl TryFrom<A> for B {}a.try_into()?Obvious, sometimes-valid relation.
impl Deref for A {}*aA is smart pointer carrying B; also enables coercions.
impl AsRef<B> for A {}a.as_ref()A can be viewed as B.
impl AsMut<B> for A {}a.as_mut()A can be mutably viewed as B.
impl Borrow<B> for A {}a.borrow()A has borrowed analog B (behaving same under Eq, …).
impl ToOwned for A { … }a.to_owned()A has owned analog B.
fn f(x: A) -> B {
    x as B
}

Convert types with keyword as if conversion relatively obvious but might cause issues. NOM

ABExampleExplanation
PointerPointerdevice_ptr as *const u8If *A, *B are Sized.
PointerIntegerdevice_ptr as usize
IntegerPointermy_usize as *const Device
NumberNumbermy_u8 as u16Often surprising behavior.
enum w/o fieldsIntegerE::A as u8
boolIntegertrue as u8
charInteger'A' as u8
&[T; N]*const Tmy_ref as *const u8
fn(…)Pointerf as *const u8If Pointer is Sized.
fn(…)Integerf as usize
 

Where Pointer, Integer, Number are just used for brevity and actually mean:

  • Pointer any *const T or *mut T;
  • Integer any countable u8i128;
  • Number any Integer, f32, f64.

Opinion 💬 — Casts, esp. Number - Number, can easily go wrong. If you are concerned with correctness, consider more explicit methods instead.

fn f(x: A) -> B {
    x
}

Automatically weaken type A to B; types can be substantially1 different. NOM

ABExplanation
&mut T&TPointer weakening.
&mut T*mut T-
&T*const T-
*mut T*const T-
&T&UDeref, if impl Deref<Target=U> for T.
TUUnsizing, if impl CoerceUnsized<U> for T.2 🚧
TVTransitivity, if T coerces to U and U to V.
|x| x + xfn(u8) -> u8Non-capturing closure, to equivalent fn pointer.
 

1 Substantially meaning one can regularly expect a coercion result B to be an entirely different type (i.e., have entirely different methods) than the original type A.

2 Does not quite work in example above as unsized can't be on stack; imagine f(x: &A) -> &B instead. Unsizing works by default for:

  • [T; n] to [T]
  • T to dyn Trait if impl Trait for T {}.
  • Foo<…, T, …> to Foo<…, U, …> under arcane 🔗 circumstances.
fn f(x: A) -> B {
    x
}

Automatically converts A to B for types only differing in lifetimes NOM - subtyping examples:

A(subtype)B(supertype)Explanation
&'static u8&'a u8Valid, forever-pointer is also transient-pointer.
&'a u8&'static u8🛑 Invalid, transient should not be forever.
&'a &'b u8&'a &'b u8Valid, same thing. But now things get interesting. Read on.
&'a &'static u8&'a &'b u8Valid, &'static u8 is also &'b u8; covariant inside &.
&'a mut &'static u8&'a mut &'b u8🛑 Invalid and surprising; invariant inside &mut.
Box<&'static u8>Box<&'a u8>Valid, Box with forever is also box with transient; covariant.
Box<&'a u8>Box<&'static u8>🛑 Invalid, Box with transient may not be with forever.
Box<&'a mut u8>Box<&'a u8>🛑 Invalid, see table below, &mut u8 never was a &u8.
Cell<&'static u8>Cell<&'a u8>🛑 Invalid, Cell are never something else; invariant.
fn(&'static u8)fn(&'a u8)🛑 If fn needs forever it may choke on transients; contravar.
fn(&'a u8)fn(&'static u8)But sth. that eats transients can be(!) sth. that eats forevers.
for<'r> fn(&'r u8)fn(&'a u8)Higher-ranked type for<'r> fn(&'r u8) is also fn(&'a u8).
 

In contrast, these are not🛑 examples of subtyping:

ABExplanation
u16u8🛑 Obviously invalid; u16 should never automatically be u8.
u8u16🛑 Invalid by design; types w. different data still never subtype even if they could.
&'a mut u8&'a u8🛑 Trojan horse, not subtyping; but coercion (still works, just not subtyping).
 
fn f(x: A) -> B {
    x
}

Automatically converts A to B for types only differing in lifetimes NOM - subtyping variance rules:

  • A longer lifetime 'a that outlives a shorter 'b is a subtype of 'b.
  • Implies 'static is subtype of all other lifetimes 'a.
  • Whether types with parameters (e.g., &'a T) are subtypes of each other the following variance table is used:
Construct1'aTU
&'a Tcovariantcovariant
&'a mut Tcovariantinvariant
Box<T>covariant
Cell<T>invariant
fn(T) -> Ucontravariantcovariant
*const Tcovariant
*mut Tinvariant

Covariant means if A is subtype of B, then T[A] is subtype of T[B].
Contravariant means if A is subtype of B, then T[B] is subtype of T[A].
Invariant means even if A is subtype of B, neither T[A] nor T[B] will be subtype of the other.

1 Compounds like struct S<T> {} obtain variance through their used fields, usually becoming invariant if multiple variances are mixed.

💡 In other words, 'regular' types are never subtypes of each other (e.g., u8 is not subtype of u16), and a Box<u32> would never be sub- or supertype of anything. However, generally a Box<A>, can be subtype of Box<B> (via covariance) if A is a subtype of B, which can only happen if A and B are 'sort of the same type that only differed in lifetimes', e.g., A being &'static u32 and B being &'a u32.

 

Coding Guides 编码指南url

Idiomatic Rust 惯用的 Rusturl

If you are used to Java or C, consider these.
如果您习惯于 Java 或 C,请考虑这些。

Idiom 成语Code 代码
Think in Expressions 思考表达式y = if x { a } else { b };
y = loop { break 5 };
fn f() -> u32 { 0 }
Think in Iterators 在迭代器中思考(1..10).map(f).collect()
names.iter().filter(|x| x.starts_with("A"))
Test Absence with ? 使用 ? 测试缺失y = try_something()?;
get_option()?.run()?
Use Strong Types 使用强类型enum E { Invalid, Valid { … } } over ERROR_INVALID = -1  enum E { Invalid, Valid { … } } 超过 ERROR_INVALID = -1
enum E { Visible, Hidden } over visible: bool  enum E { Visible, Hidden } 超过 visible: bool
struct Charge(f32) over f32  struct Charge(f32) 超过 f32
Illegal State: Impossible
非法状态:不可能
my_lock.write().unwrap().guaranteed_at_compile_time_to_be_locked = 10; 1
thread::scope(|s| { /* Threads can't exist longer than scope() */ });
Provide Builders 提供构建器Car::new("Model T").hp(20).build();
Don't Panic 不要惊慌Panics are not exceptions, they suggest immediate process abortion!
恐慌不是异常,它们暗示立即终止进程!
Only panic on programming error; use Option<T>STD or Result<T,E>STD otherwise.
只有在编程错误时才会发生 panic;否则请使用 Option<T> STDResult<T,E> STD
If clearly user requested, e.g., calling obtain() vs. try_obtain(), panic ok too.
如果用户明确请求,例如,调用 obtain()try_obtain() ,也可以触发 panic。
Generics in Moderation 适度使用泛型A simple <T: Bound> (e.g., AsRef<Path>) can make your APIs nicer to use.
一个简单的 <T: Bound> (例如, AsRef<Path> )可以使您的 API 更易于使用。
Complex bounds make it impossible to follow. If in doubt don't be creative with g.
复杂的边界使得跟踪变得不可能。如果有疑问,请不要在 g 上创造性地操作。
Split Implementations 拆分实现Generics like Point<T> can have separate impl per T for some specialization.
Point<T> 这样的泛型可以针对某些特化拥有单独的 impl
impl<T> Point<T> { /* Add common methods here */ }
impl Point<f32> { /* Add methods only relevant for Point<f32> */ }
Unsafe 不安全Avoid unsafe {}, often safer, faster solution without it.
避免 unsafe {} 通常更安全、更快速的解决方案。
Implement Traits 实现特性#[derive(Debug, Copy, …)] and custom impl where needed.
#[derive(Debug, Copy, …)] 和根据需要自定义 impl
Tooling 工具化Run clippy regularly to significantly improve your code quality. 🔥
定期运行 clippy 可显著提高您的代码质量。 🔥
Format your code with rustfmt for consistency. 🔥
使用 rustfmt 格式化您的代码以保持一致性。 🔥
Add unit tests BK (#[test]) to ensure your code works.
添加单元测试 BK#[test] ),以确保您的代码正常工作。
Add doc tests BK (``` my_api::f() ```) to ensure docs match code.
添加文档测试 BK``` my_api::f() ``` ),以确保文档与代码匹配。
Documentation 文档Annotate your APIs with doc comments that can show up on docs.rs.
使用文档注释为您的 API 添加注释,这些注释可以显示在 docs.rs 上。
Don't forget to include a summary sentence and the Examples heading.
不要忘记包括一个摘要句和示例标题。
If applicable: Panics, Errors, Safety, Abort and Undefined Behavior.
如适用:恐慌、错误、安全性、中止和未定义行为。

1 In most cases you should prefer ? over .unwrap(). In the case of locks however the returned PoisonError signifies a panic in another thread, so unwrapping it (thus propagating the panic) is often the better idea.
1 在大多数情况下,您应该更喜欢 ? 而不是 .unwrap() 。但是,在锁的情况下,返回的 PoisonError 表示另一个线程中的 panic,因此解包它(从而传播 panic)通常是更好的主意。

 

🔥 We highly recommend you also follow the API Guidelines (Checklist) for any shared project! 🔥
🔥 我们强烈建议您也遵循任何共享项目的 API 指南(清单)!🔥

 

Performance Tips 性能提示url

"My code is slow" sometimes comes up when porting microbenchmarks to Rust, or after profiling.
将微基准迁移到 Rust 后,或者在分析之后,“我的代码运行缓慢”有时会出现。

Rating 评分Name 名称Description 描述
🚀🍼Release Mode BK 🔥 发布模式 BK 🔥 Always do cargo build --release for massive speed boost.
总是为了巨大的速度提升而执行 cargo build --release
🚀🍼🚀⚠️Target Native CPU 🔗 目标本机 CPU 🔗 Add rustflags = ["-Ctarget-cpu=native"] to config.toml.
rustflags = ["-Ctarget-cpu=native"] 添加到 config.toml .
🚀🍼⚖️Codegen Units 🔗 代码生成单位 🔗 Codegen units 1 may yield faster code, slower compile.
代码生成单元 1 可能会产生更快的代码,编译速度较慢。
🚀🍼Reserve Capacity STD 保留容量 STD Pre-allocation of collections reduces allocation pressure.
集合的预分配减少了分配压力。
🚀🍼Recycle Collections STD
回收集合 STD
Calling x.clear() and reusing x prevents allocations.
调用 x.clear() 并重复使用 x 可以避免分配。
🚀🍼Append to Strings STD 追加到字符串 STD Using write!(&mut s, "{}") can prevent extra allocation.
使用 write!(&mut s, "{}") 可以防止额外的分配。
Bump Allocations 🔗 提高分配 🔗 Cheaply gets temporary, dynamic memory, esp. in hot loops.
在热循环中以低成本获取临时动态内存。
🚀🍼⚖️Replace Allocator 🔗 替换分配器 🔗 On some platforms ext. allocator (e.g., mimalloc 🔗) faster.
在某些平台上,外部分配器(例如,mimalloc 🔗 )更快。
Batch APIs 批处理 APIDesign APIs to handle multiple similar elements at once, e.g., slices.
设计 API 以一次处理多个类似元素,例如切片。
🚀🚀⚖️SoA / AoSoA 🔗Beyond that consider struct of arrays (SoA) and similar.
考虑到数组结构(SoA)等。
🚀🚀⚖️SIMD STD 🚧Inside (math heavy) batch APIs using SIMD can give 2x - 8x boost.
在(数学密集型)批处理 API 中使用 SIMD 可以提供 2 倍至 8 倍的性能提升。
Reduce Data Size 减少数据大小Small types (e.g, u8 vs u32, niches?) and data have better cache use.
小类型(例如, u8 vs u32 ,niche ? )和数据具有更好的缓存利用。
Keep Data Nearby 🔗 保持数据附近 🔗 Storing often-used data nearby can improve memory access times.
将经常使用的数据存储在附近可以提高内存访问时间。
Pass by Size 🔗 按大小传递 🔗 Small (2-3 words) structs best passed by value, larger by reference.
小(2-3 个字)的结构最好通过值传递,较大的通过引用。
🚀🚀⚖️Async-Await 🔗 异步等待 🔗 If parallel waiting happens a lot (e.g., server I/O) async good idea.
如果并行等待发生频繁(例如,服务器 I/O) async 是一个好主意。
Threading STD 线程 STD Threads allow you to perform parallel work on mult. items at once.
线程允许您同时对多个项目执行并行工作。
🚀... in app ...在应用程序中Often good for apps, as lower wait times means better UX.
通常对应用程序有好处,因为较短的等待时间意味着更好的用户体验。
🚀🚀⚖️... inside libs ...在 libs 内Opaque t. use inside lib often not good idea, can be too opinionated.
不透明的 t。在库内部使用通常不是一个好主意,可能会太主观化。
🚀🚀... for lib callers ... 用于库调用者However, allowing your user to process you in parallel excellent idea.
然而,允许用户并行处理您是一个很好的主意。
🚀🍼Buffered I/O STD 🔥 缓冲 I/O STD 🔥 Raw File I/O highly inefficient w/o buffering.
原始 File I/O 在没有缓冲的情况下效率非常低。
🚀🍼🚀⚠️Faster Hasher 🔗 更快的哈希 🔗 Default HashMap STD hasher DoS attack-resilient but slow.
默认 HashMap STD 哈希函数具有抵御 DoS 攻击的能力,但速度较慢。
🚀🍼🚀⚠️Faster RNG 更快的随机数生成器If you use a crypto RNG consider swapping for non-crypto.
如果您使用加密随机数生成器,请考虑更换为非加密随机数生成器。
🚀🚀⚖️Avoid Trait Objects 🔗
避免特质对象 🔗
T.O. reduce code size, but increase memory indirection.
为了减小代码大小,但增加内存间接引用。
🚀🚀⚖️Defer Drop 🔗 延迟删除 🔗 Dropping heavy objects in dump-thread can free up current one.
在 dump-thread 中丢弃重型对象可以释放当前对象。
🚀🍼🚀⚠️Unchecked APIs STD 未经检查的 API STD If you are 100% confident, unsafe { unchecked_ } skips checks.
如果您有 100%的信心, unsafe { unchecked_ } 将跳过检查。

Entries marked 🚀 often come with a massive (> 2x) performance boost, 🍼 are easy to implement even after-the-fact, ⚖️ might have costly side effects (e.g., memory, complexity), ⚠️ have special risks (e.g., security, correctness).
标记为🚀的条目通常具有巨大的(> 2 倍)性能提升,🍼易于在事后实施,⚖️可能具有昂贵的副作用(例如,内存,复杂性),⚠️具有特殊风险(例如,安全性,正确性)。

 

Profiling Tips 💬 性能分析提示 💬

Profilers are indispensable to identify hot spots in code. For the best experience add this to your Cargo.toml:
性能分析器对于识别代码中的热点至关重要。为了获得最佳体验,请将此内容添加到您的 Cargo.toml

[profile.release]
debug = true

Then do a cargo build --release and run the result with Superluminal (Windows) or Instruments (macOS). That said, there are many performance opportunities profilers won't find, but that need to be designed in.
然后执行 cargo build --release ,并使用 Superluminal(Windows)或 Instruments(macOS)运行结果。也就是说,有许多性能机会是性能分析器无法发现的,但需要进行设计。

 

Async-Await 101 异步等待 101url

If you are familiar with async / await in C# or TypeScript, here are some things to keep in mind:
如果您熟悉 C#或 TypeScript 中的 async/await,请记住以下几点:

Construct 构建Explanation 解释
asyncAnything declared async always returns an impl Future<Output=_>. STD
任何声明为 async 的内容始终返回 impl Future<Output=_>STD
     async fn f() {}Function f returns an impl Future<Output=()>.
函数 f 返回一个 impl Future<Output=()>
     async fn f() -> S {}Function f returns an impl Future<Output=S>.
函数 f 返回一个 impl Future<Output=S>
     async { x }Transforms { x } into an impl Future<Output=X>.
{ x } 转换为 impl Future<Output=X>
let sm = f(); Calling f() that is async will not execute f, but produce state machine sm. 1 2
调用 f() ,即 async ,不会执行 f ,而是生成状态机 sm1 2
     sm = async { g() };Likewise, does not execute the { g() } block; produces state machine.
同样,不执行 { g() } 块;生成状态机。
runtime.block_on(sm);Outside an async {}, schedules sm to actually run. Would execute g(). 3 4
async {} 之外,安排 sm 来实际运行。将执行 g()3 4
sm.awaitInside an async {}, run sm until complete. Yield to runtime if sm not ready.
async {} 内,运行 sm 直到完成。如果 sm 尚未准备好,请让出运行时。

1 Technically async transforms following code into anonymous, compiler-generated state machine type; f() instantiates that machine.
1 从技术上讲 async 将以下代码转换为匿名的、由编译器生成的状态机类型; f() 实例化该状态机。

2 The state machine always impl Future, possibly Send & co, depending on types used inside async.
2 状态机始终 impl Future ,可能 Send 等,具体取决于 async 中使用的类型。

3 State machine driven by worker thread invoking Future::poll() via runtime directly, or parent .await indirectly.
3 由工作线程驱动的状态机直接通过运行时调用 Future::poll() ,或者间接通过父级 .await 调用。

4 Rust doesn't come with runtime, need external crate instead, e.g., tokio. Also, more helpers in futures crate.
Rust 没有自带运行时,需要使用外部的 crate,例如 tokio。此外,futures crate 中还有更多的辅助工具。

At each x.await, state machine passes control to subordinate state machine x. At some point a low-level state machine invoked via .await might not be ready. In that the case worker thread returns all the way up to runtime so it can drive another Future. Some time later the runtime:

  • might resume execution. It usually does, unless sm / Future dropped.
  • might resume with the previous worker or another worker thread (depends on runtime).

Simplified diagram for code written inside an async block :

       consecutive_code();           consecutive_code();           consecutive_code();
START --------------------> x.await --------------------> y.await --------------------> READY
// ^                          ^     ^                               Future<Output=X> ready -^
// Invoked via runtime        |     |
// or an external .await      |     This might resume on another thread (next best available),
//                            |     or NOT AT ALL if Future was dropped.
//                            |
//                            Execute `x`. If ready: just continue execution; if not, return
//                            this thread to runtime.

With the execution flow in mind, some considerations when writing code inside an async construct:

Constructs 1Explanation
sleep_or_block();Definitely bad 🛑, never halt current thread, clogs executor.
set_TL(a); x.await; TL();Definitely bad 🛑, await may return from other thread, thread local invalid.
s.no(); x.await; s.go();Maybe bad 🛑, await will not return if Future dropped while waiting. 2
Rc::new(); x.await; rc();Non-Send types prevent impl Future from being Send; less compatible.

1 Here we assume s is any non-local that could temporarily be put into an invalid state; TL is any thread local storage, and that the async {} containing the code is written without assuming executor specifics.
2 Since Drop is run in any case when Future is dropped, consider using drop guard that cleans up / fixes application state if it has to be left in bad condition across .await points.

 

Closures in APIs API 中的闭包url

There is a subtrait relationship Fn : FnMut : FnOnce. That means a closure that implements Fn STD also implements FnMut and FnOnce. Likewise a closure that implements FnMut STD also implements FnOnce. STD
存在子特质关系 Fn : FnMut : FnOnce 。这意味着实现 Fn STD 的闭包也实现 FnMutFnOnce 。同样,实现 FnMut STD 的闭包也实现 FnOnceSTD

From a call site perspective that means:
从调用站点的角度来看,这意味着:

Signature 签名Function g can call …
函数 g 可以调用..
Function g accepts … 函数 g 接受…
g<F: FnOnce()>(f: F)f() at most once.
f() 最多一次。
Fn, FnMut, FnOnce
g<F: FnMut()>(mut f: F)f() multiple times. f() 多次。Fn, FnMut
g<F: Fn()>(f: F)f() multiple times. f() 多次。Fn

Notice how asking for a Fn closure as a function is most restrictive for the caller; but having a Fn closure as a caller is most compatible with any function.
注意,要求 Fn 闭包作为函数对调用者来说是最具限制性的;但是将 Fn 闭包作为调用者对任何函数来说都是最兼容的。

 

From the perspective of someone defining a closure:
从定义闭包的人的角度来看:

Closure 闭包Implements* 实现 * Comment 评论
|| { moved_s; } FnOnceCaller must give up ownership of moved_s.
调用者必须放弃对 moved_s 的所有权。
|| { &mut s; } FnOnce, FnMutAllows g() to change caller's local state s.
允许 g() 更改调用者的本地状态 s
|| { &s; } FnOnce, FnMut, FnMay not mutate state; but can share and reuse s.
可能不会改变状态;但可以共享和重用 s

* Rust prefers capturing by reference (resulting in the most "compatible" Fn closures from a caller perspective), but can be forced to capture its environment by copy or move via the move || {} syntax.
* Rust 更倾向于通过引用捕获(从调用者的角度看,这样产生的闭包最“兼容” Fn ),但可以通过 move || {} 语法强制以复制或移动方式捕获其环境。

 

That gives the following advantages and disadvantages:
这带来了以下优点和缺点:

Requiring 要求Advantage 优势Disadvantage 缺点
F: FnOnceEasy to satisfy as caller.
易于满足为调用者。
Single use only, g() may call f() just once.
仅限单次使用, g() 可能只调用 f() 一次。
F: FnMutAllows g() to change caller state.
允许 g() 更改调用者状态。
Caller may not reuse captures during g().
调用者在 g() 期间不得重复使用捕获。
F: FnMany can exist at same time.
许多可以同时存在。
Hardest to produce for caller.
对调用者来说最难产生。
 

Unsafe, Unsound, Undefined
不安全,不稳定,未定义
url

Unsafe leads to unsound. Unsound leads to undefined. Undefined leads to the dark side of the force.
不安全导致不稳定。不稳定导致未定义。未定义导致原力的黑暗面。

Safe Code 安全代码

  • Safe has narrow meaning in Rust, vaguely 'the intrinsic prevention of undefined behavior (UB)'.
    在 Rust 中,“安全”一词具有狭义,模糊地指“内在防止未定义行为(UB)”。
  • Intrinsic means the language won't allow you to use itself to cause UB.
    内在意味着语言不允许您使用自身来引起 UB。
  • Making an airplane crash or deleting your database is not UB, therefore 'safe' from Rust's perspective.
    使飞机坠毁或删除数据库不是 UB,因此从 Rust 的角度来看是“安全”的。
  • Writing to /proc/[pid]/mem to self-modify your code is also 'safe', resulting UB not caused intrinsincally.
    /proc/[pid]/mem 写入以自我修改代码也是“安全”的,导致 UB 不是内在原因。
let y = x + x;  // Safe Rust only guarantees the execution of this code is consistent with
print(y);       // 'specification' (long story …). It does not guarantee that y is 2x
                // (X::add might be implemented badly) nor that y is printed (Y::fmt may panic).

Unsafe Code

  • Code marked unsafe has special permissions, e.g., to deref raw pointers, or invoke other unsafe functions.
  • Along come special promises the author must uphold to the compiler, and the compiler will trust you.
  • By itself unsafe code is not bad, but dangerous, and needed for FFI or exotic data structures.
// `x` must always point to race-free, valid, aligned, initialized u8 memory.
unsafe fn unsafe_f(x: *mut u8) {
    my_native_lib(x);
}

Undefined Behavior (UB)

  • As mentioned, unsafe code implies special promises to the compiler (it wouldn't need be unsafe otherwise).
  • Failure to uphold any promise makes compiler produce fallacious code, execution of which leads to UB.
  • After triggering undefined behavior anything can happen. Insidiously, the effects may be 1) subtle, 2) manifest far away from the site of violation or 3) be visible only under certain conditions.
  • A seemingly working program (incl. any number of unit tests) is no proof UB code might not fail on a whim.
  • Code with UB is objectively dangerous, invalid and should never exist.
if maybe_true() {
    let r: &u8 = unsafe { &*ptr::null() };   // Once this runs, ENTIRE app is undefined. Even if
} else {                                     // line seemingly didn't do anything, app might now run
    println!("the spanish inquisition");     // both paths, corrupt database, or anything else.
}

Unsound Code

  • Any safe Rust that could (even only theoretically) produce UB for any user input is always unsound.
  • As is unsafe code that may invoke UB on its own accord by violating above-mentioned promises.
  • Unsound code is a stability and security risk, and violates basic assumption many Rust users have.
fn unsound_ref<T>(x: &T) -> &u128 {      // Signature looks safe to users. Happens to be
    unsafe { mem::transmute(x) }         // ok if invoked with an &u128, UB for practically
}                                        // everything else.
 

Responsible use of Unsafe 💬
不安全 💬 的负责使用

  • Do not use unsafe unless you absolutely have to.
    除非你绝对必须使用 unsafe ,否则不要使用。
  • Follow the Nomicon, Unsafe Guidelines, always follow all safety rules, and never invoke UB.
    遵循 Nomicon、Unsafe Guidelines,始终遵循所有安全规则,永远不要调用 UB。
  • Minimize the use of unsafe and encapsulate it in small, sound modules that are easy to review.
    尽量减少对 unsafe 的使用,并将其封装在小而健壮的模块中,便于审查。
  • Never create unsound abstractions; if you can't encapsulate unsafe properly, don't do it.
    永远不要创建不健全的抽象;如果无法正确封装 unsafe ,就不要这样做。
  • Each unsafe unit should be accompanied by plain-text reasoning outlining its safety.
    每个 unsafe 单元都应附有纯文本推理,阐明其安全性。
 

Adversarial Code 🝖 对抗性代码 🝖 url

Adversarial code is safe 3rd party code that compiles but does not follow API expectations, and might interfere with your own (safety) guarantees.
对抗性代码是安全的第三方代码,可以编译但不符合 API 预期,并可能干扰您自己的(安全)保证。

You author 您是作者User code may possibly …
用户代码可能会…
fn g<F: Fn()>(f: F) { … }Unexpectedly panic. 意外恐慌。
struct S<X: T> { … }Implement T badly, e.g., misuse Deref, …
实现 T 不当,例如,滥用 Deref ,...
macro_rules! m { … }Do all of the above; call site can have weird scope.
完成以上所有操作;调用站点可能具有奇怪的作用域。
 
Risk Pattern 风险模式Description 描述
#[repr(packed)]Packed alignment can make reference &s.x invalid.
打包对齐可能会使引用 &s.x 无效。
impl std::… for S {}Any trait impl, esp. std::ops may be broken. In particular …
任何特性 impl ,尤其是 std::ops 可能会被破坏。特别是...
     impl Deref for S {}May randomly Deref, e.g., s.x != s.x, or panic.
可能随机 Deref ,例如 s.x != s.x ,或者恐慌。
     impl PartialEq for S {}May violate equality rules; panic.
可能违反平等规则;恐慌。
     impl Eq for S {}May cause s != s; panic; must not use s in HashMap & co.
可能导致 s != s ;恐慌;在 HashMap 和其他地方不得使用 s
     impl Hash for S {}May violate hashing rules; panic; must not use s in HashMap & co.
可能违反哈希规则;恐慌;不得在 HashMap 和其他地方使用 s
     impl Ord for S {}May violate ordering rules; panic; must not use s in BTreeMap & co.
可能违反排序规则;恐慌;不得在 BTreeMap 等中使用 s
     impl Index for S {}May randomly index, e.g., s[x] != s[x]; panic.
可能会随机索引,例如, s[x] != s[x] ;恐慌。
     impl Drop for S {}May run code or panic end of scope {}, during assignment s = new_s.
在分配 s = new_s 期间可能会运行代码或在作用域结束时发生恐慌 {}
panic!()User code can panic any time, resulting in abort or unwind.
用户代码随时可能发生 panic,导致中止或展开。
catch_unwind(|| s.f(panicky))Also, caller might force observation of broken state in s.
此外,调用者可能会强制观察到 s 中的破损状态。
let … = f();Variable name can affect order of Drop execution. 1 🛑
变量名称可能会影响 Drop 执行顺序。 1 🛑

1 Notably, when you rename a variable from _x to _ you will also change Drop behavior since you change semantics. A variable named _x will have Drop::drop() executed at the end of its scope, a variable named _ can have it executed immediately on 'apparent' assignment ('apparent' because a binding named _ means wildcard REF discard this, which will happen as soon as feasible, often right away)!
1 值得注意的是,当您将变量从 _x 重命名为 _ 时,由于更改了语义,您还将更改 Drop 行为。命名为 _x 的变量将在其作用域结束时执行 Drop::drop() ,命名为 _ 的变量可以在“明显”赋值时立即执行(“明显”是因为命名为 _ 的绑定意味着通配符 REF 丢弃此绑定,这将尽快发生,通常立即发生)!

 

Implications 影响

  • Generic code cannot be safe if safety depends on type cooperation w.r.t. most (std::) traits.
    通用代码如果安全性取决于大多数( std:: )特性的类型协作,则无法保证安全。
  • If type cooperation is needed you must use unsafe traits (prob. implement your own).
    如果需要类型合作,您必须使用 unsafe 特性(可能要实现自己的)。
  • You must consider random code execution at unexpected places (e.g., re-assignments, scope end).
    您必须考虑在意想不到的地方进行随机代码执行(例如,重新赋值,作用域结束)。
  • You may still be observable after a worst-case panic.
    在最坏情况下发生 panic 后,您可能仍然可观察到。

As a corollary, safe-but-deadly code (e.g., airplane_speed<T>()) should probably also follow these guides.
作为一个推论,安全但致命的代码(例如, airplane_speed<T>() )可能也应该遵循这些指南。

 

API Stability API 稳定性url

When updating an API, these changes can break client code.RFC Major changes (🔴) are definitely breaking, while minor changes (🟡) might be breaking:
更新 API 时,这些更改可能会破坏客户端代码。 RFC 主要更改(🔴)肯定会破坏,而次要更改(🟡)可能会破坏:

 
Crates 包装箱
🔴 Making a crate that previously compiled for stable require nightly.
🔴 使之前为稳定版本编译的板条箱需要夜间版本。
🟡 Altering use of Cargo features (e.g., adding or removing features).
🟡 更改 Cargo 功能的使用(例如,添加或删除功能)。
 
Modules 模块
🔴 Renaming / moving / removing any public items.
🔴 重命名/移动/删除任何公共项。
🟡 Adding new public items, as this might break code that does use your_crate::*.
🟡 添加新的公共项,因为这可能会破坏代码,其中包含 use your_crate::*
 
Structs 结构体
🔴 Adding private field when all current fields public.
🔴 当所有当前字段都是公共字段时添加私有字段。
🔴 Adding public field when no private field exists.
🔴 当不存在私有字段时添加公共字段。
🟡 Adding or removing private fields when at least one already exists (before and after the change).
🟡 添加或删除私有字段时,至少存在一个私有字段(更改前和更改后)。
🟡 Going from a tuple struct with all private fields (with at least one field) to a normal struct, or vice versa.
🟡 从具有所有私有字段(至少一个字段)的元组结构转换为普通结构,或反之亦然。
 
Enums 枚举
🔴 Adding new variants; can be mitigated with early #[non_exhaustive] REF
🔴 添加新变体;可以通过早期 #[non_exhaustive] REF 来减轻
🔴 Adding new fields to a variant.
🔴 添加新字段到一个变体。
 
Traits 特征
🔴 Adding a non-defaulted item, breaks all existing impl T for S {}.
🔴 添加一个非默认项,会破坏所有现有的 impl T for S {}
🔴 Any non-trivial change to item signatures, will affect either consumers or implementors.
🔴 对项目签名的任何重大更改,都会影响消费者或实现者。
🟡 Adding a defaulted item; might cause dispatch ambiguity with other existing trait.
🟡 添加了一个默认项;可能会导致与其他现有特性的调度模糊。
🟡 Adding a defaulted type parameter.
🟡 添加了一个默认类型参数。
 
Traits 特征
🔴 Implementing any "fundamental" trait, as not implementing a fundamental trait already was a promise.
🔴 实现任何“fundamental”特质,因为不实现一个基本特质已经是一个承诺。
🟡 Implementing any non-fundamental trait; might also cause dispatch ambiguity.
🟡 实现任何非基本特征可能导致调度模糊。
 
Inherent Implementations 内在实现
🟡 Adding any inherent items; might cause clients to prefer that over trait fn and produce compile error.
🟡 添加任何固有项可能导致客户更喜欢它而不是 trait fn,并产生编译错误。
 
Signatures in Type Definitions
类型定义中的签名
🔴 Tightening bounds (e.g., <T> to <T: Clone>).
🔴 收紧边界(例如, <T><T: Clone> )。
🟡 Loosening bounds. 🟡 放宽限制。
🟡 Adding defaulted type parameters.
🟡 添加了默认类型参数。
🟡 Generalizing to generics.
🟡 泛型泛化。
Signatures in Functions 函数中的签名
🔴 Adding / removing arguments.
🔴 添加/删除参数。
🟡 Introducing a new type parameter.
🟡 引入一个新的类型参数。
🟡 Generalizing to generics.
🟡 泛型泛化。
 
Behavioral Changes 行为变化
🔴 / 🟡 Changing semantics might not cause compiler errors, but might make clients do wrong thing.
🔴 / 🟡 更改语义可能不会导致编译器错误,但可能会使客户端执行错误操作。
 

Misc 杂项url

These are other great guides and tables.
这些是其他优秀的指南和表格。

Cheat Sheets 速查表Description 描述
Rust Learning⭐ Rust 学习⭐Probably the best collection of links about learning Rust.
可能是关于学习 Rust 的最佳链接集合。
Functional Jargon in Rust
Rust 中的函数术语
A collection of functional programming jargon explained in Rust.
Rust 中解释的函数式编程术语集合。
Rust Iterator Cheat Sheet
Rust 迭代器速查表
Summary of iterator-related methods from std::iter and itertools.
来自 std::iteritertools 的迭代器相关方法总结。
 

All major Rust books developed by the community.
社区开发的所有主要 Rust 书籍。

Books ️📚 书籍️📚Description 描述
The Rust Programming Language
Rust 编程语言
Standard introduction to Rust, start here if you are new.
Rust 的标准介绍,如果您是新手,请从这里开始。
     API Guidelines API 指南How to write idiomatic and re-usable Rust.
如何编写符合惯用法且可重复使用的 Rust 代码。
     Asynchronous Programming 🚧
异步编程 🚧
Explains async code, Futures, …
解释 async 代码, Futures ,..
     Design Patterns 设计模式Idioms, Patterns, Anti-Patterns.
成语、模式、反模式。
     Edition Guide 版本指南Working with Rust 2015, Rust 2018, and beyond.
使用 Rust 2015、Rust 2018 以及未来版本。
     Error Handling 错误处理Language features, libraries, and writing good error code.
语言特性、库和编写良好的错误代码。
     Guide to Rustc Development
Rustc 开发指南
Explains how the compiler works internally.
解释编译器内部工作原理。
     Little Book of Rust Macros
Rust 宏小册
Community's collective knowledge of Rust macros.
社区对 Rust 宏的集体知识。
     Reference 🚧 参考 🚧 Reference of the Rust language.
Rust 语言参考。
     RFC Book RFC 图书Look up accepted RFCs and how they change the language.
查找已接受的 RFC 和它们如何改变语言。
     Performance Book 性能书籍Techniques to improve the speed and memory usage.
提高速度和内存使用的技术。
     Rust CookbookCollection of simple examples that demonstrate good practices.
展示良好实践的简单示例集合。
     Rust in Easy English
Rust in Easy English Rust 简单英语
Explains concepts in simplified English, good alternative start.
解释了简单英语中的概念,是一个很好的替代起点。
     Rust for the Polyglot Programmer
多语言程序员的 Rust
A guide for the experienced programmer.
经验丰富的程序员指南。
     Rustdoc Book Rustdoc 书籍Tips how to customize cargo doc and rustdoc.
如何自定义 cargo docrustdoc 的提示。
     RustonomiconDark Arts of Advanced and Unsafe Rust Programming.
高级和不安全的 Rust 编程的黑暗艺术。
     Unsafe Code Guidelines 🚧
不安全代码指南 🚧
Concise information about writing unsafe code.
有关编写 unsafe 代码的简明信息。
     Unstable Book 不稳定的书籍Information about unstable items, e.g, #![feature(…)].
有关不稳定项目的信息,例如, #![feature(…)]
The Cargo Book 货物手册How to use cargo and write Cargo.toml.
如何使用 cargo 并编写 Cargo.toml
The CLI Book CLI 书籍Information about creating CLI tools.
创建 CLI 工具的信息。
The Embedded Book 嵌入式书籍Working with embedded and #![no_std] devices.
处理嵌入式和 #![no_std] 设备。
     The Embedonomicon 嵌入式编程指南First #![no_std] from scratch on a Cortex-M.
从头开始在 Cortex-M 上 #![no_std]
The WebAssembly Book WebAssembly 书籍Working with the web and producing .wasm files.
处理网络并生成 .wasm 个文件。
     The wasm-bindgen Guide  wasm-bindgen 指南How to bind Rust and JavaScript APIs in particular.
如何特别绑定 Rust 和 JavaScript API。

For more inofficial books see Little Book of Rust Books.
要查看更多非官方书籍,请参阅《Rust 小书集》。

 

Comprehensive lookup tables for common components.
常见组件的综合查找表。

Tables 📋 表格 📋Description 描述
Rust ForgeLists release train and links for people working on the compiler.
列出了编译器工作人员的发布计划和链接。
     Rust Platform Support Rust 平台支持All supported platforms and their Tier.
所有支持的平台及其层级。
     Rust Component History Rust 组件历史Check nightly status of various Rust tools for a platform.
检查平台上各种 Rust 工具的夜间状态。
ALL the Clippy Lints
所有的 Clippy Lints
All the clippy lints you might be interested in.
您可能感兴趣的所有 Clippy 代码检查。
Configuring Rustfmt 配置 RustfmtAll rustfmt options you can use in .rustfmt.toml.
您可以在 .rustfmt.toml 中使用的所有 rustfmt 选项。
Compiler Error Index 编译器错误索引Ever wondered what E0404 means?
曾经想过 E0404 代表什么吗?
 

Online services which provide information or tooling.
在线服务提供信息或工具。

Services ⚙️ 服务 ⚙️Description 描述
crates.ioAll 3rd party libraries for Rust.
Rust 的所有 3 个 rd 方库。
std.rsShortcut to std documentation.
std 文档的快捷方式。
stdrs.devShortcut to std documentation including compiler-internal modules. 🝖
包括编译器内部模块在内的 std 文档的快捷方式。 🝖
docs.rsDocumentation for 3rd party libraries, automatically generated from source.
从源代码自动生成的 3 个第三方库的文档。
lib.rsUnofficial overview of quality Rust libraries and applications.
Rust 库和应用程序的非官方质量概述。
caniuse.rsCheck which Rust version introduced or stabilized a feature.
检查哪个 Rust 版本引入或稳定了一个特性。
releases.rsRelease notes for previous and upcoming versions.
以前和即将发布版本的发布说明。
query.rsA search engine for Rust.
Rust 的搜索引擎。
Rust PlaygroundTry and share snippets of Rust code.
尝试并分享 Rust 代码片段。
 

Printing & PDF 打印和 PDFurl

Want this Rust cheat sheet as a PDF? Download the latest PDF here. Alternatively, generate it yourself via File > Print and then "Save as PDF" (works great in Chrome, has some issues in Firefox).
想要将这份 Rust 备忘单转换为 PDF 吗?在此下载最新的 PDF。或者,通过“文件” > “打印”,然后选择“另存为 PDF” 来自行生成(在 Chrome 中效果很好,在 Firefox 中可能会有一些问题)。