feat: add initial implementation of Google Rust Style Guide as an Agent Skill
ZhenYi committed
Added skills/google-rust-style/references/api-design.md skills/google-rust-style/references/api-design.md +218 −0 View skills/google-rust-style/references/api-design.md
@@ -0,0 +1,218 @@
1# API 设计:输入输出、类型、trait 与 API 属性
2
3提炼自指南的 Function inputs and outputs / Types / Traits / Concurrency / Macros / Other Rust features 章节。
4
5总纲:**库代码**(供其他项目复用)必须遵守 API 设计规则;**应用代码**(单一程序内部)作为强烈建议,优先简单直接、避免过早泛化与抽象。
6
7## 函数输入与输出
8
9### 不可变借用参数取最灵活的形态
10
11传"数据本身"的引用,不传智能指针/容器/包装类型的引用:
12
13| 用 | 不用 | 原因 |
14|---|---|---|
15| `&T` | `&Box<T>` | 借 box 里的数据 |
16| `&[T]` | `&Vec<T>` | 接受任意切片而非特定容器 |
17| `&str` | `&String` | 接受字符串切片而非 owned 字符串的引用 |
18| `Option<&T>` | `&Option<T>` | 借 Option 里的数据 |
19
20例外:预期非线性字符数据(Rope/Cord)。对应 clippy:`borrowed_box`、`ptr_arg`。
21理由:不绑定具体容器/包装的引用让函数更通用,调用方无需先复制。
22
23### 返回值:迭代器 vs 所有权集合
24
25- 库代码尽量返回迭代器(具体类型或 `impl Iterator`)而非 `Vec<T>`。
26- 应用代码:返回 `Vec<T>` 没问题,简单优先。
27
28返回 `Vec` 更合适的情形:多数调用方需要 owned vector;实现本来就构造 vector;返回值需要随机索引;算法更适合 `for` 循环且强制分配影响不大;函数目的就是创建新集合;返回已存在的 vector。
29
30### 参数:迭代器 vs 切片
31
32- 高复用性的库代码只需遍历输入时,接受迭代器或 `impl IntoIterator`(更灵活、免拷贝、可组合)。
33- 应用代码:接受 `&[T]` 更简单即可。
34
35### 接受 `Into`
36
37- 库 API 用户实参类型多样、调用点体验优先时,考虑 `impl Into<T>` 代替 `T`(如 `impl Into<String>` 可直接收 `String` 或 `&str` 字面量)。权衡泛型的代码膨胀与类型推断复杂度,不是多多益善。
38- 应用代码几乎不用 `impl Into<T>` 参数。
39
40### 参数用 `enum` 不用 `bool`
41
42参数用途不明显时用 `enum`。坚持用 `bool` 时,在参数列表加行内注释说明用途。
43
44### 错误上报:`Option` / `Result` / `panic!`
45
46- `Option`:失败原因显而易见、更多细节无益。如 `checked_add` 的整数溢出。
47- `Result`:可恢复的失败,调用方需要上下文区分失败模式并恢复,常源于外部因素(I/O、网络)。如 `open_file` 需区分 NotFound 与 PermissionDenied。
48- `panic!`:报告 bug 与被违反的不变量(如索引越界)——应在代码里修,不是运行时处理;粗粒度恢复或可借助 `catch_unwind`(其使用限制见 implementation.md)。
49
50注:部分代码库选择完全不用 panic,连被破坏的不变量也要求用 `Result` 报告。
51
52例外:面向开发者的二进制可用 panic 报非致命错误;测试断言可用 panic。
53
54## 类型
55
56### newtype vs 类型别名
57
58以下情况用 newtype:类型有显著语义差异;值得拥有自己的 API;想保留日后更换底层类型的自由(尤其不控制全部用例时);类型安全需要(`Date` 内部用 newtype 区分 `Day`/`Month`/`Year`)。
59
60### 命名字段优先于元组
61
62元组下标(`.0`、`.1`)很快会看不懂。例外:单字段 newtype 元组结构体;极局部、不会混淆的场景。
63
64## trait
65
66### 实现时机
67
68低层库代码应预判用户需求、主动实现;应用代码按需添加。
69
70### 实现标准库 trait 而非自定义方法
71
72方法与标准库 trait 的目的和行为一致时实现该 trait:`impl FromStr for Foo` 而不是在 `Foo` 上写 `fn from_str(&str) -> Self`。为可发现性可以两者都保留。对应 clippy `should_implement_trait`。
73
74### 能 `#[derive()]` 就不用手写
75
76### 泛型优先于 `dyn Trait`
77
78库中函数参数用 `T: Trait` / `impl Trait` 优于 `dyn Trait`。例外:代码体积敏感。
79理由:dyn 有胖指针与 vtable 开销、阻碍内联等编译器优化;部分 trait 不 dyn 兼容(含泛型函数、无 `self` 的关联函数、返回 `Self` 的 trait)。
80
81### 何时定义 trait
82
83只为以下目的定义 trait:泛型编程(`T: Trait` 约束);接受或返回 `impl Trait` / `dyn Trait`;定义扩展 trait。其余情况用固有实现(inherent impl)。**不要用 trait 来组织代码。**
84
85### 扩展 trait(extension trait)
86
87给其他 crate 的类型加方法时用扩展 trait——唯一目的是给该类型加方法,不用于泛型或动态分发。命名带 `Ext` 后缀(原文记法 `~Ext`,如 `ForeignTypeExt`)。原则上由原类型的 owning team 同时维护扩展 trait。例外:预期广为人知、价值巨大的基础库/框架扩展。注意:作为输入约束的 trait(如 `DateLike`,实现于一堆外部类型)不属此列。
88
89```rust
90trait ForeignTypeExt {
91 fn additional_method(&self);
92}
93impl ForeignTypeExt for ForeignType { … }
94```
95
96也可为所有实现某外部 trait 的类型统一实现扩展 trait,效果等同于给该外部 trait 添加默认方法:
97
98```rust
99trait ForeignTraitExt {
100 fn additional_method(&self);
101}
102impl<T: ForeignTrait> ForeignTraitExt for T { … }
103```
104
105### 重要 trait 的实现建议
106
107- 公开字段的类型:考虑实现所有子字段都实现的 trait。
108- 错误类型:尽量实现 `Copy`(含 `String` 等非 Copy 字段时除外)。
109- `Copy`:有理由相信类型将长期保持 Copy 就实现。
110- `Clone`:除表示外部资源的类型外都应实现。
111- `Default`:实现了 `new()` 或有默认状态就实现(clippy `new_without_default`)。
112- `PartialEq` / `Eq`:想让用户用 `==` 就实现 `PartialEq`;实现 `Eq` 注意额外的自反性要求。
113- `PartialOrd` / `Ord`:同理;`Ord` 要求全序。
114- map key:类型可能用作 key 或被缓存 → 实现 `Hash` + `Eq`;再有清晰全序 → 加 `Ord`。
115
116### 重要 `From` 实现配对显式构造方法
117
118重要的 `From` impl 若是主要构造方式之一,配一个固有 `::new()` / `::new_from_foo()` / `::from_foo()`。
119
120### options 结构体实现 `Default`
121
122全公开字段、主要作为函数"选项袋"的 struct 应实现 `Default`,以支持 `Struct { a: 0, ..Default::default() }`。
123
124## 并发
125
126- 永远不要从 poisoned mutex 里取内部数据,无论用例多诱人。
127- [chrome] 不用 `async` / `.await`。
128- [chrome] 不通过标准库起新线程,用 sequences。
129- [Fuchsia] 用 `fuchsia_sync::Mutex`,不用 `std::sync` 或 `parking_lot`。
130
131## 宏
132
133API 表达优先级:常规函数/类型/trait/对象/模块 **>** `macro_rules!` 宏 **>** 其他代码生成(如 genrule)**>** `proc_macro`。
134
135决定用宏或代码生成前权衡成本:IDE、代码搜索等工具对宏代码支持更差;宏会制造语言方言,增加跨代码库工作成本;LSC 更难更贵。
136
137`macro_rules!` 基于 AST 展开,比文本式代码生成更不易碎。
138
139## API 属性与访问器
140
141### getter / setter 命名
142
143- `foo()`:返回 `&T`,或 `T: Copy` 时按值返回。
144- `foo_mut()`:返回 `&mut T`。
145- `take_foo()`:清掉值(置 `None` 或默认态)并返回旧值。
146- `set_foo()`:按值设置。
147- `with_foo()` / `with_mut_foo()`:经闭包访问,`object.with_foo(|foo| …)`。
148- `replace_foo()`:按值设置并返回旧值。
149
150```rust
151impl Stuff {
152 fn foo(&self) -> &Foo { … }
153 fn foo_mut(&mut self) -> &mut Foo { … }
154 fn take_baz(&mut self) -> Option<Baz> { … }
155 fn set_foo(&mut self, foo: Foo) { … }
156 fn with_bar<R>(&self, f: impl FnOnce(&Bar) -> R) -> R { … }
157 fn with_mut_bar<R>(&self, f: impl FnOnce(&mut Bar) -> R) -> R { … }
158 fn replace_foo(&mut self, foo: Foo) -> Foo { … }
159}
160```
161
162### 闭包式访问器 `with_foo()` 的适用场景
163
164- 属性在内部可变性包装里(`Mutex` / `RefCell`):闭包提供访问作用域,优于直接返回 `MutexGuard<T>`(那会泄漏实现细节)。
165- 改属性后需要跟进校验/收尾、`set_foo()` 不可用时(如属性类型昂贵或无法克隆)。
166
167闭包的返回值通常从 `with_foo()` 透传。
168
169需要同时提供只读与可变两个闭包访问器时,按惯例命名 `with_foo()` / `with_mut_foo()`;否则 `with_foo()` 也常用于可变访问。
170
171### API 成套实现
172
173实现了 `len()` 就同时实现 `is_empty()`(clippy `len_without_is_empty`)。
174
175### `#[doc(hidden)]` 视为私有
176
177不访问不属于自己代码的 `#[doc(hidden)]` 条目。
178
179### `const` fn 慎用
180
181公开函数只在预期将持续保持 `const`(或承诺帮调用方迁移)时才标 `const`——`const` 改回普通函数是破坏性变更。
182
183### 运算符重载只用于数学/逻辑本义
184
185不做"语法糖"式的重载。
186
187### 公开 enum 加 `#[non_exhaustive]`
188
189跨团队使用的公开 API enum 标 `#[non_exhaustive]`:强制调用方 match 留通配臂(`_ => …`),未来加变体不破坏编译。
190
191例外:enum 永不变更(描述既有本体如 `enum Color { Red, Green, Blue }`;两态等价 bool 如 `enum Visibility { Visible, Hidden }`);或承诺用 LSC 修复破坏。使用范围很小的 enum 可不遵守。clippy `exhaustive_enums`。
192
193### 公开字段的 struct 加 `#[non_exhaustive]`
194
195跨团队使用、含公开字段的 struct 同理:加新字段(哪怕私有)会破坏 struct 字面量构造;`#[non_exhaustive]` 使外部只能经构造函数创建。
196
197例外:字段描述稳定本体(如 Rectangle);承诺 LSC;需要用户能使用 FRU 语法(`Person { name: "foo", ..Default::default() }`)——与 `#[non_exhaustive]` 互斥。
198
199### `#[must_use]`
200
201- 函数:忽略返回值就无法正确使用时——纯函数(如 `HashMap::get()`);返回值承载错误或关键信息(返回类型本身已 `#[must_use]` 的,如 `Result`,不用重复标注)。
202- 类型:将被上述函数返回的类型——错误类型(类似 `Result` 或 `StatusOr`);惰性求值类型(不取返回值就不产生副作用)。
203
204### 不要在 `main()` 之前运行代码
205
206不用 `ctor` crate 之类手段。
207
208### unsafe 代码
209
210没有等价安全实现时才写 unsafe。必须写时:
211
212- 封装为安全抽象,与业务逻辑尽量隔离;理想:单独 crate、除标准库外极少依赖。
213- 加以 `SAFETY:` 开头的注释,解释代码为何正确。
214- 给技术理由:为什么不能用等价的安全写法实现;若理由是性能,给出 benchmark。
215
216### 不用 unstable 特性
217
218例外:Android 嵌入式确需的(review 后一般会批);[chrome] style arbiters 可能对整库白名单一小批有稳定路径的特性;Fuchsia 另见其指引。
Added skills/google-rust-style/references/implementation.md skills/google-rust-style/references/implementation.md +123 −0 View skills/google-rust-style/references/implementation.md
@@ -0,0 +1,123 @@
1# 实现层面:所有权、错误处理与代码细节
2
3提炼自指南的 Ownership and borrowing / Implementation concerns / Use the right per-codebase test framework 章节。
4
5## 所有权与借用
6
7### 避免 `Rc` / `Arc`
8
9优先唯一所有权与借用。Rust 通常能不靠共享所有权指针表达对象图;这些指针有运行时开销和自身复杂性,从其他语言来的工程师容易过快使用。
10
11例外:替代的所有权与借用结构复杂到难以编写、理解或维护(review 时判断)。
12
13### 借用优先于深拷贝
14
15`.clone()` 只在真正需要深拷贝时用,不当借用的替代品;让代码顺应 Rust 的所有权与借用规则来设计。借用关系过分复杂时,clone 是务实选择;选择时同时考虑性能需求。
16
17注:clone `Rc`/`Arc` 指针不是深拷贝,是其正常用法。
18
19## 不要过度依赖类型推断
20
21写到"熟悉代码库的人能推断出类型"的程度。类型加在变量声明上,而不是加 turbofish;若编译器逼着写 turbofish,用 `_` 占位通常可以。
22
23应加显式类型的场景:调用泛型返回类型的方法(`.into()`、`.parse()`);复杂迭代器链的结果。
24
25## 模式匹配优于 check-then-unwrap
26
27输入数据保证不会 panic 时,用模式匹配向编译器证明正确性:
28
29```rust
30// 好:match 向编译器证明了 x 是 Some,显然不会 panic
31if let Some(value) = option {
32 use_value(value);
33}
34
35// 不好:unwrap 的正确性依赖运行时检查
36if option.is_some() {
37 use_value(option.unwrap());
38}
39```
40
41### `expect` 优于 `unwrap`
42
43类型系统表达不了的不变量必须 panic 时,用 `expect` 记录理由。
44
45## 匹配 `#[non_exhaustive]` enum 时列出模式
46
47尽量在 match 中列出全部变体;不关心的变体归入通配臂(`Shape::Triangle | _ => {}`);只关心特定变体时用 `if let` 或 `let … else`。例外:只关心特定变体但 match 比 `if let` 更干净时。
48
49## 用上下文字符串说清断言
50
51`assert!` 的可选格式串用于说明断言为何应当成立、或为何被违反。特别值得加上下文的场景:本想加注释时(格式串的好处是会进日志);失败信息会到用户手里时;记录某个值有助于理解失败时;区分"调用方误用 API"与"实现有 bug"时。
52
53```rust
54// 解释断言为何成立
55assert!(
56 values.is_sorted(),
57 "`values` is populated from a `PriorityQueue`, so we expect it to be sorted"
58);
59
60// 记录值
61assert!(refund > 0, "Refund must be positive, got {refund:?}");
62
63// 标记 API 误用
64assert!(self.stream.is_some(), "Call connect() before executing queries");
65
66// 不好:只复述条件
67assert!(values.is_sorted(), "values should always be sorted");
68```
69
70## 迭代器组合器链 vs 直接迭代
71
72- 避免长而复杂的组合器链(尤其含条件、改外部状态的)。
73- 不要在 `for` 头部构造链:先赋给具名变量再迭代——减少杂乱,变量名还能说明链的用途。
74- 避免使用 `Iterator::for_each`(确有理由除外),`for` 循环通常更好读。
75- 短链、组合器本身承载大量逻辑时组合器更优:`values.iter().any(|&v| v > threshold)` 好于手写 flag + break。
76
77```rust
78// 不好:for 头部构造链
79for bug in bugs.iter().filter_map(|d| parse(d).ok()).filter(|b| b.priority <= Priority::P1) { … }
80
81// 好:具名变量
82let urgent_bugs = bugs
83 .iter()
84 .filter_map(|d| parse(d).ok())
85 .filter(|b| b.priority <= Priority::P1);
86for bug in urgent_bugs { … }
87```
88
89```rust
90// 不好:链里夹条件与外部状态
91let _processed: Vec<_> = items
92 .into_iter()
93 .map(transform_that_may_fail)
94 .map(|result| { if result.is_err() { error_count += 1; } result })
95 .filter_map(Result::ok)
96 .collect();
97
98// 好:对应的 for 循环
99let mut processed = Vec::with_capacity(items.len());
100for item in items {
101 match transform_that_may_fail(item) {
102 Ok(val) => processed.push(val),
103 Err(_) => error_count += 1,
104 }
105}
106```
107
108## 禁用 `panic::catch_unwind`
109
110第一方 Rust 代码禁用。例外:仅作纵深防御且绝不依赖其任何性质(代码库须已尽力避免 panic),且仅在可能以 `panic=unwind` 运行的环境中适用(Chrome、Android、Fuchsia 均要求 `panic=abort`,不适用)。
111
112## 拼接与替换用 `format!` / `write!`
113
114- 拼接超过两段字符串:`format!("{a}{b}{c}")` 而非 `a + b + c`。
115- 对字面量做替换:用格式串而非 `str::replace`。
116
117理由:比 `+` 拼接分配更少;标准格式串优于自造模板语法。
118
119## 测试框架
120
121多数 Google 代码库用各自测试框架而非 `#[test]`:Chrome 用 rust_gtest_interop(Rust 测试并入 C++ 测试二进制);Fuchsia 用 `#[fuchsia::test]`。
122
123(注:通用 Rust 项目照常 `#[test]` + `cargo test` 即可——此句为使用本技能时的补充说明,非指南原文。)
No newline at end of file
Added skills/google-rust-style/references/naming-and-documentation.md skills/google-rust-style/references/naming-and-documentation.md +62 −0 View skills/google-rust-style/references/naming-and-documentation.md
@@ -0,0 +1,62 @@
1# 命名与文档
2
3提炼自指南的 Naming 与 When and how to write documentation 章节。
4
5## 命名
6
7### 方法命名
8
9遵循 Rust 标准库的方法命名风格。`as_…()` / `to_…()` / `into_…()` 等前缀要与相应的 `self` 参数约定匹配(借用 / 复制 / 消耗)。对应 clippy `wrong_self_convention`;另见 Comprehensive Rust 的[命名约定](https://google.github.io/comprehensive-rust/idiomatic/foundations-api-design/predictable-api/naming-conventions.html)。
10
11### 生命周期命名
12
13- 生命周期用描述性名称,类型生命周期尤其如此。
14- 例外:极端泛型的抽象(如 `Cow`);能用匿名生命周期 `'_` 的地方就用;表达方法输入与输出关系、或局部 higher-ranked 约束(`for<'a>`)时可用单字符——此类最多两个,再多强烈建议改用描述性名称。
15
16### 泛型参数命名
17
18用与所代表事物相关的短名(单字符或多字符)。单字母可以,但字母应暗示类型,理想取自最重要的 trait bound。无约束场景用 `T`、`U` 即可(如 `Vec<T>`)。
19
20### 扩展 trait 命名
21
22以 `Ext` 结尾(原文记法 `~Ext` 后缀),如 `ForeignTypeExt`。
23
24### 初始化/构造函数命名
25
26- 构造器:`new()`;多于一个时用 `new_with_foo()`;返回 `Result` 时用 `try_new()`。
27- 值到值转换:`from_foo()`,并配对关联的 `From` 实现(何时应实现 `From` 见[官方文档](https://doc.rust-lang.org/std/convert/trait.From.html#when-to-implement-from))。
28
29### 避免缩写
30
31不使用项目外的人不认识的缩写(尤其首字母缩写);不用删字母式缩写。
32
33例外:Wikipedia 上的常见缩写;项目外不会混淆的缩写(如 `IpAddr`)——由作者与 reviewer 判断,倾向仍然是不缩写。
34
35## 文档注释
36
37### 公开 API 必须有文档
38
39可用 `missing_docs` lint 辅助。最佳实践:
40
41- 覆盖示例:不必每个函数都有示例,但应在某处提供足够示例覆盖 crate 的主要功能,让人了解用法。
42- 可能因畸形输入 panic 的函数,必须文档化 panic 条件。
43- unsafe 函数与 trait:清晰文档化不变量(invariants)。
44- 使用大写开头和标点。
45- 不解释语言基础。反面示例:给 `MockFileSystem` 写 "A mock implementation of the FileSystem trait, intended to be used in unit tests."。
46- 不简单复述:`/// Removes an element.` 配 `remove_element()` 不如不写(这种情况可 allow lint)。
47- 枚举变体的文档可省略,名字自解释时尤其如此。
48
49### 格式
50
51- `///` 文档化紧随其后的条目:函数、struct、enum、trait、类型别名。
52- `//!` 文档化模块或库本身,放文件顶部。
53- 遵循官方 Rust 风格指南对 doc comment 的要求;用 Markdown。
54- `//` 用于实现注释、用户不关心的 TODO、注释掉的代码等非文档内容。
55- 直接写 `///` / `//!`,不要用宏生成文档——让文档在源码中直接可读。
56- 鼓励文档注释与实现注释混用,各说各的:
57
58```rust
59/// Finds the first `FooItem` with the given `name`, or `None` if not present.
60// TODO: crbug.com/12345 - `name` should be &str, not String.
61pub fn get_named(items: &[FooItem], name: String) -> Option<&FooItem> { … }
62```
Added skills/google-rust-style/references/organization-and-formatting.md skills/google-rust-style/references/organization-and-formatting.md +115 −0 View skills/google-rust-style/references/organization-and-formatting.md
@@ -0,0 +1,115 @@
1# 代码组织与格式
2
3提炼自指南的 Code organization 与 Code formatting and aesthetics 章节。带 [chrome] / [Fuchsia] 标记的规则只适用于对应代码库,通用项目不套用。
4
5## crate 与模块结构
6
7术语:crate 是编译单元,总是包含一个无名的"根模块";module 是 crate 内的代码组织单元,用于控制名称可见性,可嵌套、可跨文件拆分。
8
9### 倾向小 crate [chrome]
10
11- Chromium 中倾向小 crate,理想(但非必须)是单文件、聚焦单一抽象;能拆成小 crate 就拆。
12- Chromium 中一个 crate 对应一条 `rust_static_library` 规则,可包含一个或多个 `.rs` 文件。
13- 理由:代码库规模巨大,新增依赖会影响整个构建图;细粒度目标利于并行编译与构建缓存。
14- 根模块可以 re-export 叶子子模块的公开 API,让子模块成为 crate 的实现细节(使用者无需感知)。
15- 先判断这些 API 是否必须在同一 crate,再考虑是否用子模块组织;本规则对有无子模块的 crate 同样适用。
16- trait impl 一致性(coherence)规则强制多个类型和 trait 放进同一个库,或构建大型基础库时,允许更大的 crate。
17
18### 单目录扁平布局 [chrome]
19
20- 一个 `rust_library` 的 `.rs` 文件必须放在同一目录;不要用子目录组织同一 crate 的文件——觉得需要子目录,说明 crate 太大该拆了。
21- 例外:`//third_party` 中同时用 Cargo 构建的代码遵循常规 Cargo 目录结构。
22
23### 文件与叶子模块按主要条目命名
24
25叶子模块的主要用户定义条目是 `Foo` 时,模块与文件命名为 `mod foo` / `foo.rs`。不围绕特定抽象的叶子模块可自由命名。目的:一眼看出文件内容。
26
27### 非叶子模块不实现 API
28
29非叶子模块中只应有模块声明(不是定义)和 re-export。允许:少量"把东西粘起来"的核心实现代码;叶子模块内的 `mod test` 与 `#[cxx::bridge]` 等跨语言绑定子模块。
30
31## imports
32
33### 禁用 glob imports
34
35不要 `use foo::*`。可自行斟酌使用的例外:
36
37- `use super::*`(内联模块)
38- `use Enum::*`(enum 自身的方法体内、主要处理该 enum 的函数内)
39- `pub use submodule::*`(非叶子模块的 re-export)
40- C++ 互操作合并命名空间:把多个 crate 中同名 C++ 命名空间子模块合并为一个**私有**模块(如 `mod absl { pub use status::absl::*; pub use strings::absl::*; }`),仅限此用途且不得公开。
41
42第三方 crate 鼓励 prelude 时由 reviewer 裁量;自己不要定义 prelude。
43理由:glob 增加 LSC(大规模变更)工具的负担,且在无交叉引用工具时难以判断类型来源。
44
45### 一条 `use` 只从一个模块导入
46
47对应 rustfmt 设置 `imports_granularity = Module`:`use` 语句的 `{..}` 内不应再出现 `::`。
48
49```rust
50// 好
51use foo::Foo;
52use foo::bar::{Bar, Baz};
53
54// 不好
55use foo::{Foo, bar::Bar};
56use foo::{Foo, bar::{Bar, Baz}};
57```
58
59### trait 导入尽量局部化
60
61在函数体内 `use` trait,除非该 trait 的方法在整个文件中大量使用。
62
63```rust
64fn foo(s: &str) -> Result<u8, std::num::ParseIntError> {
65 use std::str::FromStr; // 函数内导入,不放模块顶部
66 u8::from_str(s)
67}
68```
69
70### 顶层函数调用带模块名
71
72调用其他模块/crate 的顶层函数时,导入模块并用 `modulename::functionname()`:
73
74```rust
75use std::mem;
76let x = mem::transmute(y); // 好
77// 不用:use std::mem::transmute; transmute(y);
78```
79
80例外:函数名已充分消歧(如 C++ 顶层函数);[chrome] 小型单一用途第一方 crate 的函数;模块名本身易冲突(如多个 crate 定义同名 C++ 命名空间子模块)。
81理由:维持"未限定的小写名可以认为是本模块函数"的惯例。
82
83### 类型名导入后不加限定
84
85默认用 `use regex::Regex` 之后写 `Regex`,不写 `regex::Regex`。
86
87例外:名称歧义(可写 `io::Error` 或 `use std::io::Error as IoError`);大型类型组(如 rustc 的 `hir` 模块含大量相关类型);宏与生成代码;依赖极多导致 import 块过大。
88
89### [chrome] 导入机制
90
91Chromium 使用 `chromium::import!()`。
92
93## 格式化
94
95### 用对格式化工具
96
97格式交给工具(Chromium 用 `git cl format`)。rustfmt 配置要点(指南允许 stable 工具链用不了 nightly 选项的代码库放弃对应项):
98
99```toml
100max_width = 100 # 已稳定
101hex_literal_case = "Lower" # 已稳定
102format_macro_matchers = true # nightly-only,stable 工具链会忽略
103```
104
105- 每行最多 100 列。
106- 十六进制字面量用小写(`0xab123cdef`,不是 `0xAB123CDEF`)。
107- 字面量中的不可见字符用转义,如零宽连接符写 `\u{200D}`。
108- 注:`imports_granularity = "Module"` 对应上面的 use 粒度规则;它与 `format_macro_matchers` 都是 nightly-only 选项,只在 nightly rustfmt 下生效(如 `cargo +nightly fmt`),按项目工具链取舍。
109
110### `#[rustfmt::skip]` 只用于两种情况
111
112- 手工对齐确有可读性收益:多行相似代码需要对齐、构造矩阵的函数等。
113- 生成代码(更好的做法是用 genrule 生成)。
114
115个人风格偏好不允许 skip 格式化。
Added skills/google-rust-style/references/source-text.md skills/google-rust-style/references/source-text.md +2107 −0 View skills/google-rust-style/references/source-text.md
@@ -0,0 +1,2107 @@
1# 原文全文(机器提取)
2
3自动提取自 https://google.github.io/styleguide/rustguide.html(2026-10-25 抓取),仅做了 HTML 转文本处理,未改写内容。浓缩规则与之冲突时以本文为准。开头的重复目录可忽略。
4
5注意:HTML 转文本时丢失了正文中的超链接 URL(仅 `Eq` / `Ord` 两处保留);Clippy lint、官方 Rust Style Guide、Comprehensive Rust、Fuchsia 测试文档等出处需回原页查看。
6
7---
8
9# Google Style Guides
10
11
12
13
14# Rust Style Guide
15
16
17- Rust Style Guide
18
19- Background
20
21- Scope
22
23- Goals of the style guide
24
25
26
27
28- Follow public Rust style rules
29
30- Apply API design rules in context
31
32- Code organization
33
34- Prefer small crates [chrome]
35
36- Use flat file layout for `rust_library` sources [chrome]
37
38- Name source files and leaf modules after the primary user-defined item
39
40- Don’t implement APIs in non-leaf modules
41
42- Don’t use glob imports
43
44- A `use` statement should import items from one module
45
46- Prefer locally-scoped trait imports
47
48- Qualify calls to top-level functions with a module name
49
50- Type names should be imported and used unqualified
51
52- Use the appropriate import mechanism [chrome]
53
54
55
56
57- Code formatting and aesthetics
58
59- Use the appropriate formatting tool
60
61- Opting out of automatic formatting
62
63
64
65
66- Ownership and borrowing
67
68- Avoid `Rc` and `Arc`
69
70- Prefer borrows over deep copies
71
72
73
74
75- Function inputs and outputs
76
77- Accept flexible references for immutable data
78
79- Iterators vs. owned collections in return types
80
81- Iterators vs. slices in function parameters
82
83- Accepting `Into`
84
85- Prefer `enum` over `bool` in APIs
86
87- Reporting errors
88
89
90
91
92- Types
93
94- Newtypes versus type aliases
95
96- Prefer named fields over tuples and non-newtype tuple structs
97
98
99
100
101- Traits
102
103- Add trait implementations when they become necessary
104
105- Implement known standard library traits instead of custom methods
106
107- Use `#[derive()]` if possible
108
109- Generics versus `dyn Trait`
110
111- When to define a trait versus an inherent implementation
112
113- Extension traits
114
115- Specific guidance for important traits
116
117- Pair important `From` impls with explicit constructor methods
118
119- Options structs should implement Default
120
121
122
123
124- Concurrency
125
126- Handling poison
127
128- Don’t use `async` / `.await` [chrome]
129
130- Don’t start new threads through the Rust standard library [chrome]
131
132- Use `fuchsia_sync::Mutex` [Fuchsia]
133
134
135
136
137- Macros
138
139- Naming
140
141- Naming methods
142
143- Naming lifetimes
144
145- Naming generic parameters
146
147- Naming extension traits
148
149- Naming initialization functions
150
151- Avoid abbreviations
152
153
154
155
156- When and how to write documentation
157
158- Other Rust features
159
160- Unsafe code
161
162- No unstable features
163
164- Getters and setters
165
166- More on accessors that accept closures
167
168
169
170
171- Implement expected API sets together
172
173- Do not access items marked `#[doc(hidden)]` that you don’t own
174
175- Use `const` functions responsibly
176
177- Avoid overloading for non-mathematical purposes
178
179- Apply `#[non_exhaustive]` to publicly-exposed enums
180
181- Apply `#[non_exhaustive]` to public structs with public fields
182
183- `#[must_use]` on functions
184
185- `#[must_use]` on types
186
187- Do not run code before `main()`
188
189
190
191
192- Implementation concerns
193
194- Don’t overuse type inference
195
196- Prefer pattern matching over check-then-unwrap
197
198- Prefer `expect` over `unwrap`
199
200- Don’t omit patterns on `non_exhaustive` enums when matching
201
202- Use context strings to clarify assertions
203
204- Don’t use iterator combinator chains when direct iteration is clearer
205
206- Don’t call `panic::catch_unwind`
207
208- Prefer `format!` / `write!` for concatenation and substitution
209
210
211
212
213- Use the right per-codebase test framework
214
215
216
217
218This document is a style guide for the usage of the Rust programming language
219at Google. In this context, “style” refers to more than just formatting; it
220includes guidance on API and implementation design.
221
222Rust is used in many places, including
223google3,
224Android, ChromeOS, Fuchsia, and Chrome, and we’d like for Rust usage at Google
225to be consistent both within and across codebases. In addition to bringing
226consistency to our Rust code, style guidance also helps establish a standard of
227quality.
228
229## Background
230
231### Scope
232
233The current scope of authority of the rules outlined in this guide:
234
235
236- In Android, Chromium, and other codebases: This style guide has been
237developed in consultation with other codebases, and they intend to start
238applying it. These codebases may have their own rules about how strictly
239this is expected to be applied. Expect more information here as these
240codebases adopt this guide.
241
242### Goals of the style guide
243
244By and large, we have this document for
245the same reasons we have a C++ style guide.
246
247Most style rules come from one or more of the goals listed below.
248
249 Style rules should prioritize readability and maintainability over writeability
250
251 We expect our code to be around for long periods of time, and we
252consider a little bit of extra effort applied during code writing to be
253worth it in the long run if the style rule improves readability.
254
255
256
257 Style rules should favor better automation
258
259 Large-Scale Changes (LSCs)
260are common at Google, and consistency helps
261make LSCs easier to carry out.
262
263
264
265 Style rules should be consistent with the wider Rust ecosystem where possible
266
267 The broader Rust ecosystem already has a pretty good amount of consistency
268in style, and we should rely on that where possible to reduce surprise and make
269it less work to learn Google’s Rust style.
270
271
272
273 Style rules should pull their weight
274
275 Every Rust developer and reviewer at Google has to keep these style rules
276in mind: as such, we should be careful to include rules that have a tangible
277benefit.
278
279
280
281 Style rules may help avoid minor style disagreements
282
283 There are many cases where reasonable people may disagree about a style, and
284we expect that disagreement to show up often on CLs. Having a style rule helps
285avoid having to rehash this each time. Rules in this category that do not have other
286benefits should be kept to a minimum.
287
288
289
290## Follow public Rust style rules
291
292Follow the official public Rust style rules to the extent they don’t conflict
293with this style guide.
294
295
296-
297 Rust Style Guide
298
299
300
301- Most code formatting conventions are enforced automatically by rustfmt.
302
303
304
305
306-
307 Rust API Guidelines
308
309
310
311A “conflict” would be a case where this style guide suggests a pattern that is
312discouraged, or counter to the primary encouraged pattern in the Rust style
313guide.
314
315Why does the guidance in this style guide deviate from regular Rust style rules?
316
317Most style guides have three goals: consistency, readability, and encouraging
318good API design. Regardless of the specific choices made, it helps everyone to
319have these choices made beforehand to limit bikeshedding.
320
321This style guide shares those goals, but it also has an additional goal not seen
322as often: smoothing the way for Large-Scale Changes (LSCs). Large codebases like
323many of the ones at Google occasionally need to run codebase-spanning
324refactorings that are assisted by tooling: for this to work well, the code
325should be something tooling has an easy time working with. Consistency helps for
326this, but so does having deliberate refactor-friendly patterns.
327
328## Apply API design rules in context
329
330When applying rules that relate to API design, you should distinguish two types
331of code:
332
333
334-
335 Library code
336
337
338
339- Intended for use by other projects (applications or other libraries).
340
341- Solves a relatively general problem.
342
343
344
345
346-
347 Application code
348
349
350
351- Intended for use in a single application.
352
353- Solves a more specific problem.
354
355
356
357
358For library code, style guide rules that concern API design are binding.
359
360For application code, the rules on API design are a strong recommendation. As
361you apply them, keep in mind that since application code is written to solve a
362specific problem, it should generally favor simplicity and directness over broad
363reusability. Avoid premature generalization and abstraction; focus on what is
364required to meet the immediate need.
365
366## Code organization
367
368Terminology:
369
370
371-
372 A crate is a unit of compilation. A crate always contains a nameless Rust
373module, the “root module”.
374
375
376
377-
378 A Rust module is a unit of code organization within a crate. Rust modules
379are used to control visibility of names. Modules can be nested. They can
380also be used to split code across files and directories.
381
382
383
384The following sections convey that in Chromium, it is preferable to not make
385use of all possibilities of splitting modules across files.
386
387### Prefer small crates [chrome]
388
389Prefer small crates in Chromium; ideally, but not necessarily, a single file
390(focusing on one abstraction). If your code can be split up into small crates,
391do so.
392
393A crate corresponds to a single `rust_static_library` (chrome) rule, which may
394contain one or more `.rs` files.
395
396Additional considerations:
397
398
399-
400 The root module is allowed to `re-export` public APIs from
401`leaf submodules`, making submodules an implementation detail of the crate
402(as users don’t need to know about these submodules).
403
404
405
406-
407 This rule about small crates applies equally to crates with and without
408submodules. First, evaluate whether the APIs need to be in the same crate,
409and only then consider whether submodules could help organize the APIs.
410
411
412
413-
414 If you decide to use submodules, follow the
415expected file structure.
416
417
418
419Larger crates are allowed when
420trait impl coherence rules
421force multiple types and traits to be included in one library, or if you’re
422building a large foundational library.
423
424Rationale
425
426Fine-grained library targets are recommended in Chromium due to the massive size
427of our codebase, non-local effects of adding dependencies in the build graph,
428and to improve performance of parallel compilation and build caching.
429
430### Use flat file layout for `rust_library` sources [chrome]
431
432In Chromium `.rs` source files belonging to one `rust_library` (one Rust crate)
433must reside in a single directory.
434
435Don’t use subdirectories to organize files that belong to a single crate. If
436organizing one crate’s files into subdirectories feels necessary, this is a
437strong indication that the crate has grown too large and should
438be split.
439
440This crate layout is intentionally different from the conventional Cargo
441directory structure typically used in open-source repositories.
442
443Exception: Rust code in `//third_party` that is also built with
444Cargo should follow the conventional Cargo
445directory structure.
446
447Rationale
448
449The approach in Chromium is driven by the following factors:
450
451
452- Based on the preference for small crates, most
453`rust_library` targets will only contain one source file.
454
455- Because of the above point, creating a directory for each `rust_library`
456target would result in most directories containing only one source file.
457
458- Multi-file `rust_library` targets should not create dedicated directories
459for submodules either; this ensures a consistent approach.
460
461### Name source files and leaf modules after the primary user-defined item
462
463When a `leaf module` has a primary user-defined item (e.g., `Foo`), the module
464should be named after that item (e.g., `mod foo` and `foo.rs`).
465
466Leaf modules that are not primarily about any particular abstraction can be
467named as desired.
468
469Rationale
470
471This makes it easy to identify the content/purpose of a source file or leaf
472module at a glance.
473
474### Don’t implement APIs in non-leaf modules
475
476The only items in non-leaf modules should be module declarations (not
477definitions) and `re-exports`.
478
479Note that the definition of `leaf modules` allows the following sub-modules:
480`mod test` and cross-language binding modules like `#[cxx::bridge]`.
481
482Exceptions:
483
484
485- Having a small amount of core “ties things together” implementation code in
486a non-leaf module may be fine. The goal is to not have a lot of code in
487these modules.
488
489Rationale
490
491This makes it easier to find things, and avoids mixing structure and contents.
492
493### Don’t use glob imports
494
495Don’t use glob imports, except in the following situations where you may
496optionally do so at your own discretion:
497
498
499- `use super::*` for inline modules
500
501- `use enum::*` in method bodies of enums, and functions that are primarily
502dealing with that enum
503
504- `pub use submodule::*` for non-leaf modules
505
506-
507 C++ interop: Since the same namespace (in C++) is a submodule in different
508Rust crates (in Rust), you may merge the namespaces into a private copy
509using glob imports. For example:
510
511
512```rust
513mod absl {
514 pub use status::absl::*;
515 pub use strings::absl::*;
516}
517```
518
519
520
521 In this hypothetical example, you can use `absl::Status` and `absl::StrCat`
522from Rust, the same way you would from C++, instead of spelling them as
523`status::absl::Status` and `strings::absl::StrCat`.
524
525 This must only be used for merging C++ namespaces, and the resulting merged
526module must not be public.
527
528
529
530If using third-party crates that encourage a prelude, it is up to the reviewer’s
531discretion to allow it.
532
533This also means that defining preludes should be avoided.
534
535Rationale
536
537Glob imports increase toil for code janitors running LSCs, and make it harder to
538know where a type comes from in contexts without xrefs.
539
540### A `use` statement should import items from one module
541
542This rule corresponds to the rustfmt setting `imports_granularity = Module`.
543
544Basically, there should not be any `::`’s inside the `{..}` block of a `use`
545statement. For example:
546
547```rust
548use foo::Foo;
549use foo::bar::Bar;
550use foo::bar::Baz;
551```
552
553```rust
554use foo::Foo;
555use foo::bar::{Bar, Baz};
556```
557
558```rust
559use foo::{Foo, bar::Bar};
560```
561
562### Prefer locally-scoped trait imports
563
564Import traits within function bodies, unless the trait’s methods are used
565extensively throughout the file.
566
567```rust
568fn foo(s: &str) -> Result<u8, std::num::ParseIntError> {
569 // Import the trait within a function, not at the module scope.
570 use std::str::FromStr;
571
572 u8::from_str(s)
573}
574```
575
576### Qualify calls to top-level functions with a module name
577
578To use top-level functions defined in other modules or crates, import their
579module and call them with `modulename::functionname()`. For example:
580
581```rust
582use std::mem;
583
584let x = mem::transmute(y);
585```
586
587```rust
588use std::mem::transmute;
589
590let x = transmute(y);
591```
592
593Exceptions:
594
595
596- When importing functions with sufficiently disambiguated names, e.g.,
597functions from C++ (where it is typical to call top-level (free) functions
598directly).
599
600-
601 In Chromium, when importing functions from
602small, single-purpose first-party crates.
603
604
605
606- When the module name itself is prone to collisions. For example, when the
607module name is a C++ namespace name, and multiple crates define the same
608submodules.
609
610Rationale
611
612Many Rust codebases consistently keep a style such that unqualified lowercase
613names are assumed local, so `foo()` can be assumed to be from the same module.
614This rule largely exists to avoid reviewer disagreements, the benefit is mostly
615consistency and a minor edge on reading code without xrefs.
616
617### Type names should be imported and used unqualified
618
619By default, types and traits should be referenced in code without using their
620module path, e.g., code should use `Regex`, not `regex::Regex`, with a
621`use regex::Regex` at the top of the file or potentially in the relevant
622function.
623
624Exceptions:
625
626
627- In cases where there are ambiguities, it is acceptable to directly reference
628types with common names like `io::Error`. It is also acceptable to rename
629(`use std::io::Error as IoError`).
630
631- In cases where you have a large “group” of types, e.g. the
632`hir module in rustc`
633which contains a large number of HIR types.
634
635- In macros and generated code; where requiring a `use` is counterproductive.
636
637- In code with lots of dependencies, where importing everything would lead to
638a very large import block with little benefit.
639
640Rationale
641
642This rule largely exists to avoid reviewer disagreements.
643
644### Use the appropriate import mechanism [chrome]
645
646
647- Chrome Use `chromium::import!()`.
648
649## Code formatting and aesthetics
650
651### Use the appropriate formatting tool
652
653Use the appropriate formatting tool (e.g., `git cl format` in Chromium).
654
655Configuration (for style guide authors)
656
657A codebase may choose to not apply the following `rustfmt` options if they care
658about building on stable and the option is unavailable on their stable Rust:
659
660
661-
662 Maximum of 100 columns per line:
663`max_width = 100`
664
665
666
667-
668 Usage of lowercase alphabets in hex literals (`0xab123cdef` as opposed to
669`0xAB123CDEF`):
670`hex_literal_case = Lower`
671
672
673
674-
675 Macro matcher formatting:
676`format_macro_matchers = true`
677
678
679
680-
681 Usage of escapes for invisible characters in literals. E.g., if you wish to
682have text containing a Zero-Width joiner, use `\u{200D}`.
683
684
685
686### Opting out of automatic formatting
687
688You may opt out of automatic formatting using `#[rustfmt::skip]`, but only in
689the following situations:
690
691
692- Manual alignment – If you have a situation-specific reason to have a
693snippet of code line up in a particular way (e.g., multiple similar lines of
694code that you want to remain aligned for readability, or a
695matrix-constructing function).
696
697- Generated code (ideally, use a genrule instead).
698
699Important: Formatting should not be skipped for personal style choices.
700
701## Ownership and borrowing
702
703### Avoid `Rc` and `Arc`
704
705Prefer unique ownership and borrowing over `Rc` and `Arc` for managing memory.
706
707Exception:
708
709
710- Use `Rc` and `Arc` when the alternative ownership and borrowing structure
711would be unreasonably complex to write, understand, or maintain. This is a
712judgment call to be discussed during code review.
713
714Rationale
715
716Generally, Rust allows representing object graphs without using shared ownership
717smart pointers. These pointers add runtime overhead and their own unique
718complexity. Engineers coming from other languages might tend to use `Rc` and
719`Arc` too quickly.
720
721### Prefer borrows over deep copies
722
723Use `.clone()` when you genuinely need a deep copy of an object.
724
725Avoid using `.clone()` as a substitute for borrowing. Design code that works
726naturally with Rust’s ownership and borrowing rules. However, if the borrowing
727relationships become excessively complex, `.clone()` can be a pragmatic choice.
728
729Consider the performance needs of the code while choosing between cloning and
730borrowing.
731
732Note: This advice does not apply to cloning `Rc` or `Arc` pointers. Cloning
733reference-counted pointers does not create a deep copy, and is an expected way
734to use them.
735
736Rationale
737
738Deep copies can be expensive to make due to memory allocation and data copying.
739
740## Function inputs and outputs
741
742### Accept flexible references for immutable data
743
744When functions accept borrowed, immutable data, use a reference type that
745affords the most flexibility. Pass references to the data itself instead of
746references to smart pointers, containers, or wrappers.
747
748 |
749
750
751 | Use
752 | Instead of
753 | Why?
754
755
756
757
758
759
760 | `&T`
761 | `&Box<T>`
762 | Borrow the data inside the box
763
764
765
766
767 | `&[T]`
768 | `&Vec<T>`
769 | Accept any slice instead of specific containers
770
771
772
773
774 | `&str`
775 | `&String`
776 | Accept a string slice instead of references to owned strings
777
778
779
780
781 | `Option<&T>`
782 | `&Option<T>`
783 | Borrow the data inside the Option
784
785
786
787
788Exceptions:
789
790
791- When expecting non-linear character data such as Rope/Cord.
792
793For context, see Clippy lints
794`borrowed_box`
795and
796ptr_arg.
797
798Rationale
799
800Accepting reference types that don’t mention specific smart pointers,
801containers, or wrappers makes functions more versatile and performant: callers
802can pass data held in a variety of ways without copying it first.
803
804### Iterators vs. owned collections in return types
805
806Prefer returning iterators (either concrete types or `impl Iterator`) where
807possible over returning `Vec<T>`.
808
809Note: In application code, returning a `Vec<T>` is fine if it simplifies the
810code and if flexibility and performance advantages of iterators are not clearly
811needed.
812
813Exceptions:
814
815
816- Most callers will need to construct an owned vector.
817
818- The function’s implementation naturally constructs a vector.
819
820- The returned value will likely need to be randomly indexed.
821
822- The algorithm works better as a `for` loop and the forced allocation doesn’t
823matter too much.
824
825- The function’s intended purpose is creating a new owned collection.
826
827- The function is returning a pre-existing vector.
828
829Rationale
830
831Highly reusable library code generally should strive to provide more flexible
832and performant APIs. Returning an iterator allows callers to choose how to
833consume the data: collect it into a vector, process it in a loop, or chain
834further iterator adapters. Some of these options allow users to avoid
835unnecessary allocations.
836
837In application code, the usage patterns for a function are often easier to
838predict. If it is clear that performance is not a concern, or that data would be
839collected into a vector anyway, returning a vector makes for a simpler API.
840
841### Iterators vs. slices in function parameters
842
843Highly reusable library code should accept iterators or `impl IntoIterator` if
844it only needs to iterate over the input.
845
846Note: In application code, accepting a slice `&[T]` is fine if it simplifies the
847code and if flexibility and performance advantages of iterators are not clearly
848needed.
849
850Rationale
851
852Highly reusable library code generally should strive to provide more flexible
853and performant APIs. Functions that accept iterators offer callers:
854
855
856- More flexibility (data can be supplied from any collection)
857
858- Efficiency (data does not need to be copied into a contiguous piece of
859memory)
860
861- Composability (the function works better with iterator chains)
862
863In application code, the usage patterns for a function are often easier to
864predict. If it is clear that performance is not a concern, or that callers would
865always have a vector anyway, accepting a slice makes for a simpler API.
866
867### Accepting `Into`
868
869When designing library APIs that accept a `T` but users are likely to have
870various types, consider accepting `impl Into<T>` instead of `T` if call-site
871ergonomics are paramount.
872
873Tip: This should be balanced against code bloat concerns; it is not a
874requirement to use lots of `Into<T>` in your code.
875
876Note: Application code should almost never use `impl Into<T>` parameters.
877
878Rationale
879
880Using `impl Into<T>` allows a function to directly accept various arguments of
881various compatible types. For example, a function accepting `impl Into<String>`
882could be called with a `String` or a `&str` literal directly.
883
884The tradeoff here is balancing the convenience of avoiding a `.into()` at the
885callsite against the cost of generics (more complex API signature, increased
886code size, sometimes even type inference difficulties).
887
888### Prefer `enum` over `bool` in APIs
889
890Use `enum` function parameters instead of `bool` in cases where the purpose of
891the parameter is not obvious.
892
893If you do use `bool`, consider using an inline comment to document the purpose
894of the `bool` in an argument list.
895
896### Reporting errors
897
898Choose the error reporting mechanism that fits your API contract: `Option`,
899`Result`, or `panic!`.
900
901Use `Option` for simple failures where the cause is obvious and the caller
902would not benefit from further details. This is best for standard, anticipated
903outcomes like a missing value or a parsing mismatch.
904
905```rust
906// Good: The cause of the failure is obvious (integer overflow). No further
907// details could be reasonably provided.
908fn checked_add(a: u32, b: u32) -> Option<u32> { ... }
909```
910
911Use `Result` for recoverable failures where the caller needs context to
912handle the error. These are often “unavoidable” errors caused by external
913factors (like I/O or network) that even correctly implemented code cannot
914prevent with checks ahead of time. Nevertheless, the caller can reasonably
915anticipate the kinds of errors (a file-related function can fail with an I/O
916error). The error details allow the caller to distinguish failure modes and
917recover appropriately.
918
919```rust
920// Good: The caller needs to know *why* it failed (NotFound vs PermissionDenied).
921fn open_file(path: &Path) -> Result<File, io::Error> { ... }
922```
923
924Use `panic!` to report bugs and violated invariants. These errors are
925avoidable: the program is missing a check, and is calling an operation without
926fulfilling a precondition. These defects must be fixed in the code, not handled
927at runtime, although coarse-grained recovery might be possible with
928`catch_unwind`.
929
930```rust
931// Good: Panics if the invariant (index must be in bounds) is violated.
932// This indicates a bug in the caller's logic.
933impl<T> MyVec<T> {
934 pub fn remove(&mut self, index: usize) -> T {
935 if index >= self.len() {
936 panic!("index out of bounds");
937 }
938 // ...
939 }
940}
941```
942
943Note: Some codebases may choose to avoid panics entirely, and require even
944broken invariants to be reported via `Result`.
945
946Exceptions:
947
948
949- Developer-facing binaries may use panics for non-fatal errors.
950
951- Tests may use panics for assertions.
952
953## Types
954
955### Newtypes versus type aliases
956
957Use a
958newtype
959instead of a type alias in the following cases:
960
961
962- If the type you are defining has notable semantic differences.
963
964- For types that warrant an API of their own.
965
966- If you want the flexibility to change the underlying type later, especially
967if you don’t control all usages of your type.
968
969- For type safety, if it’s easy for the types to get mixed up. For example, a
970`Date` type may use newtypes to distinguish `Day`, `Month`, and `Year`
971numbers in its internal calculations.
972
973### Prefer named fields over tuples and non-newtype tuple structs
974
975Prefer types with named fields over tuples, as tuple indexes (`.0`, `.1`, …)
976quickly become confusing.
977
978Exceptions:
979
980
981- Newtype tuple structs (tuple structs with only one field).
982
983- In very local contexts where there is unlikely to be any confusion.
984
985## Traits
986
987### Add trait implementations when they become necessary
988
989As a general rule, low-level library code should anticipate users’ needs
990proactively, while application code should add trait impls as needed.
991
992### Implement known standard library traits instead of custom methods
993
994If a method matches the purpose and behavior of a standard library trait,
995implement that trait. For example, instead of writing
996`fn from_str(&str) -> Self` on `Foo`, you should `impl FromStr for Foo`.
997
998It is acceptable to have both the method and the trait impl for discoverability
999reasons.
1000
1001For context, see Clippy lint
1002`should_implement_trait`
1003(list of traits).
1004
1005### Use `#[derive()]` if possible
1006
1007Manual implementations should be avoided if they can be expressed as a
1008`#[derive()]`.
1009
1010### Generics versus `dyn Trait`
1011
1012In libraries, prefer accepting generics (`T: Trait` or `impl Trait`) in function
1013parameters over `dyn Trait`.
1014
1015Exceptions:
1016
1017
1018- Cases where code size matters.
1019
1020Rationale
1021
1022
1023-
1024 Efficiency
1025
1026
1027
1028- Additional indirection: Creating a `dyn Trait` requires setting up a fat
1029pointer, and a vtable lookup is required for every call of a function on
1030the trait.
1031
1032- If a function takes a `dyn Trait`, the compiler can’t perform certain
1033optimizations that it could if the function was generic, such as
1034inlining calls to functions of the trait.
1035
1036
1037
1038
1039-
1040 Some traits are not
1041`dyn` compatible.
1042For example, a trait is not `dyn` compatible if it has generic functions,
1043associated functions without a `self` parameter, or functions that return
1044`Self`.
1045
1046
1047
1048### When to define a trait versus an inherent implementation
1049
1050Define a trait only for the following purposes:
1051
1052
1053-
1054 To enable generic programming (to use `T: Trait` in constraints of generic
1055functions and types).
1056
1057
1058
1059-
1060 To accept or return an `impl Trait` or `dyn Trait`.
1061
1062
1063
1064-
1065 To define an extension trait (but see also the caveats
1066in the section on extension traits).
1067
1068
1069
1070In all other cases where you want to implement functionality for a type, use an
1071inherent implementation.
1072
1073Don’t use traits merely to organize code.
1074
1075### Extension traits
1076
1077An
1078extension trait
1079is a trait that adds methods to a type from a different crate.
1080
1081What differentiates an extension trait from other traits is that its sole
1082purpose is to add methods to the type; it is not intended for use in generics
1083(`T: Trait`, `impl Trait`) or dynamic dispatch (`dyn Trait`). To indicate this,
1084the name of an extension trait should carry the suffix `~Ext` (for example,
1085`ForeignTypeExt`).
1086
1087In general, the team that owns the original type should also own the extension
1088trait.
1089
1090Exceptions:
1091
1092
1093- Extension methods that are expected to become well known and provide
1094significant value, for example, in foundational libraries / frameworks.
1095
1096Note: This rule is specifically about extension traits. It is relatively common
1097to define a trait as an input trait (e.g., `DateLike`) and implement it on a
1098bunch of foreign types.
1099
1100Examples
1101
1102```rust
1103extern crate foreign_crate;
1104use foreign_crate::ForeignType;
1105
1106trait ForeignTypeExt {
1107 fn additional_method(&self);
1108}
1109
1110impl ForeignTypeExt for ForeignType {
1111 fn additional_method(&self) { ... }
1112}
1113```
1114
1115It is also possible to define an extension trait for every type that implements
1116some foreign trait. Effectively, this is equivalent to adding default methods to
1117the foreign trait:
1118
1119```rust
1120extern crate foreign_crate;
1121use foreign_crate::ForeignTrait;
1122
1123trait ForeignTraitExt {
1124 fn additional_method(&self);
1125}
1126
1127impl<T: ForeignTrait> ForeignTraitExt for T {
1128 fn additional_method(&self) { ... }
1129}
1130```
1131
1132Rationale
1133
1134When the same team owns the extension trait and the type being extended, this
1135helps avoid method name conflicts between the base type and the extension trait
1136or between two extension traits.
1137
1138### Specific guidance for important traits
1139
1140
1141-
1142 Types with public fields: Consider implementing traits implemented by
1143all subfields.
1144
1145
1146
1147-
1148 Error types: Implement the `Copy` trait whenever possible. `Copy` types
1149are simpler to manage and propagate because they can be passed by value
1150without moving ownership. An example of a case where this is not possible is
1151if the error must contain non-`Copy` fields like a `String`.
1152
1153
1154
1155-
1156 `Copy`: Implement whenever it is reasonably clear that the type will
1157continue to be `Copy` in the future.
1158
1159
1160
1161-
1162 `Clone`: Most types should implement `Clone` unless they represent some
1163external resource.
1164
1165
1166
1167-
1168 `Default`: Implement if the type implements `new()` or otherwise has a
1169default state. For context, see Clippy lint
1170`new_without_default`.
1171
1172
1173
1174-
1175 `PartialEq` / `Eq`: If you want users to use the `==` operator,
1176prefer implementing `PartialEq` over `Eq`. When you do implement `Eq`, be
1177aware of the additionally required reflexivity (details:
1178https://doc.rust-lang.org/std/cmp/trait.Eq.html).
1179
1180
1181
1182-
1183 `PartialOrd` / `Ord`: If you want users to use the `<` or `>`
1184operators, prefer implementing `PartialOrd` over `Ord`. When you do
1185implement `Ord`, be aware that it requires total ordering (details:
1186https://doc.rust-lang.org/std/cmp/trait.Ord.html).
1187
1188
1189
1190-
1191 Map keys
1192
1193
1194
1195- If you think it is likely that a type will be used as a map key or
1196otherwise cached, implement `Hash` and `Eq`.
1197
1198- If, in addition, the type has a clear total ordering, implement `Ord`
1199(and any traits it needs).
1200
1201
1202
1203
1204### Pair important `From` impls with explicit constructor methods
1205
1206If a type has an important `From` impl that is expected to be one of the primary
1207ways of constructing it, add an inherent `::new()`, `::new_from_foo()`, or
1208`::from_foo()` method.
1209
1210### Options structs should implement Default
1211
1212Structs with all-public fields that are primarily used as a “bag of options” for
1213a function should implement `Default`.
1214
1215Rationale
1216
1217This enables convenient use of struct update syntax
1218(`Struct { a: 0, ..Default::default()}` ).
1219
1220## Concurrency
1221
1222### Handling poison
1223
1224Never reach inside a poisoned mutex to get at its insides, no matter how
1225tempting the use case may seem.
1226
1227### Don’t use `async` / `.await` [chrome]
1228
1229Don’t use `async` / `.await` in Chromium.
1230
1231### Don’t start new threads through the Rust standard library [chrome]
1232
1233In Chromium, prefer to use sequences instead of threads.
1234
1235### Use `fuchsia_sync::Mutex` [Fuchsia]
1236
1237Use Fuchsia’s mutex type, rather than one from `std::sync` or `parking_lot`.
1238
1239## Macros
1240
1241When considering how to express an API, prefer in order:
1242
1243
1244-
1245 Regular Rust functions, types, traits, objects, and modules. (Avoid macros,
1246code generation, and metaprogramming where possible).
1247
1248
1249
1250-
1251 `macro_rules!`-style macros.
1252
1253
1254
1255-
1256 Other code generation strategies (e.g. `genrule`)
1257
1258
1259
1260-
1261 `proc_macro` macros.
1262
1263
1264
1265When you decide to use a macro or code generation, please weigh the benefits
1266against the costs:
1267
1268
1269- IDEs, Code Search and other developer tools will work less well on code that
1270uses macros.
1271
1272- Macros can create dialects of the language that make it harder for engineers
1273to work across the codebase.
1274
1275- Large scale changes are more difficult and expensive to apply.
1276
1277Rationale
1278
1279Prefer non-macro facilities: Macros can create dialects of the language that
1280make it harder for engineers to work across the codebase. When a reader sees a
1281usage of a macro, they can make fewer assumptions about that code than if it
1282didn’t use a macro. Macros are harder to write correctly than regular Rust code.
1283
1284Use `macro_rules!` for simple code generation: Since Rust macros operate on
1285the AST, they can be less fragile than textual code generation.
1286
1287## Naming
1288
1289### Naming methods
1290
1291Follow the Rust standard library style for naming methods. See also the guidance
1292on
1293naming conventions
1294in the Comprehensive Rust course.
1295
1296Specific considerations:
1297
1298
1299- Use prefixes such as `as_...()`, `to_...()`, or `into_...()` with the
1300appropriate `self` convention. See also
1301this section
1302of the Rust API Guidelines and the Clippy lint
1303`wrong_self_convention`.
1304
1305### Naming lifetimes
1306
1307Lifetimes should have descriptive names, especially type lifetimes.
1308
1309Exceptions:
1310
1311
1312- Type lifetimes that are extremely generic abstractions like `Cow`.
1313
1314- It is fine to use anonymous lifetimes (`'_`) where they work.
1315
1316- Single-character lifetimes are okay when they are simply expressing the
1317relationship between a method’s input and output, or needed for a local
1318higher-ranked lifetime bounds (`for<'a>`). Up to two such local lifetimes
1319are fine, if more are needed, we strongly advise you to use descriptive
1320names.
1321
1322### Naming generic parameters
1323
1324Use a short name for your generic parameters (either single or multi character),
1325related to the kind of thing they represent. Single-letter generics are okay,
1326but the letter chosen should be somewhat indicative of the object type, ideally
1327taken from the most important trait bound.
1328
1329`T` or `U` are fine when the generics are in a relatively unbound context; i.e.
1330it is an API intended for use with most types, like `Vec<T>`.
1331
1332### Naming extension traits
1333
1334When naming an extension trait, give the name an `~Ext`
1335suffix (for example, `ForeignTypeExt`).
1336
1337### Naming initialization functions
1338
1339Follow these guidelines when naming initialization functions:
1340
1341
1342-
1343 Constructors: Use `new()`, or `new_with_foo()` if there is more than one. If
1344the constructor returns a `Result`, use `try_new()`.
1345
1346
1347
1348-
1349 Value-to-value conversions: Use `from_foo()` with an associated `From` impl.
1350See
1351here
1352for details on when an operation can be considered to be a value-to-value
1353conversion.
1354
1355
1356
1357### Avoid abbreviations
1358
1359Don’t use abbreviations (especially acronyms and initialisms) that someone
1360outside your project is unlikely to know. Don’t abbreviate by deleting letters
1361within a word.
1362
1363See also the
1364Google C++ Style Guide.
1365
1366Exceptions:
1367
1368
1369- Common abbreviations found in Wikipedia.
1370
1371- Abbreviations that are unlikely to be confusing to people outside of your
1372project, for example `IpAddr`. You and your reviewer should make this
1373determination. In general, the preference should still be not to abbreviate.
1374
1375## When and how to write documentation
1376
1377Add documentation comments to public APIs, potentially using the `missing_docs`
1378lint to help with this.
1379
1380Best practices for documentation comments:
1381
1382
1383-
1384 Consider including examples: It is not necessary for every function to have
1385examples, but enough functionality should be covered in examples somewhere
1386to give an idea of how the crate works.
1387
1388
1389
1390-
1391 Always document panic cases for functions which may panic due to malformed
1392input.
1393
1394
1395
1396-
1397 Clearly document invariants for unsafe functions and traits.
1398
1399
1400
1401-
1402 Use capitalization and punctuation.
1403
1404
1405
1406-
1407 Don’t explain the basics of the programming language. For example, don’t do
1408the following:
1409
1410
1411```rust
1412struct MockFileSystem { ... }
1413
1414/// A mock implementation of the FileSystem trait, intended to be used in unit tests.
1415impl FileSystem for MockFileSystem
1416```
1417
1418
1419
1420
1421
1422Exceptions:
1423
1424
1425-
1426 Comments should say something that the code does not already say. If there’s
1427nothing insightful to say, it is better to omit the comment than to repeat
1428the function name in a trivial way. For example, don’t do the following
1429(it’s fine to `allow` the lint in that case):
1430
1431
1432```rust
1433/// Removes an element.
1434pub fn remove_element() -> Element {}
1435```
1436
1437
1438
1439
1440
1441-
1442 It is generally okay to omit documentation on individual enum variants,
1443especially if their name is self-explanatory.
1444
1445
1446
1447How to format documentation comments
1448
1449Follow these guidelines when writing documentation comments:
1450
1451
1452- Use `///` comments to document items following the comment, such as
1453functions, structs, enums, traits, and type aliases.
1454
1455- Use `//!` comments to document the module or the library itself. These
1456comments should be placed at the top of the file.
1457
1458- Follow the rules laid out in
1459the official Rust style guide on doc comments.
1460
1461- Use Markdown syntax.
1462
1463- Use ordinary comment syntax (`//`) for non-documentation comments, such as
1464implementation comments, TODOs that are not interesting for users, commented
1465out source code, etc.
1466
1467- Prefer to document things in a straightforward manner, using `///` and `//!`
1468comments, rather than generating documentation from macros. This makes the
1469documentation directly readable when viewing or modifying the source code.
1470
1471It is acceptable, and even encouraged, to mix doc comments (`///` and `//!`) and
1472ordinary comments (`//`). If you have one thing you wish to document publicly,
1473and another thing you want to note as an implementation comment, then use both!
1474For example:
1475
1476```rust
1477/// Finds the first `FooItem` with the given `name`, or `None` if not present.
1478// TODO: crbug.com/12345 - `name` should be &str, not String.
1479pub fn get_named(items: &[FooItem], name: String) -> Option<&FooItem> {...}
1480```
1481
1482Rationale
1483
1484Many, though not all, languages have a different commenting convention (such as
1485extra `*` characters) for doc comments as opposed to implementation comments.
1486Rust and Python are notable for not just having different commenting
1487conventions, but an actual different syntax entirely. This has concrete benefits
1488to the Rust ecosystem:
1489
1490
1491- Doc comments can be consumed by tooling, including documentation generators
1492like `rustdoc`, IDE features, and Kythe.
1493
1494- Doc comments have a standard structure and formatting rules (Markdown),
1495allowing for rich text in those contexts.
1496
1497- Errors in applying doc comment syntax (e.g., applying it to an expression
1498instead of a documentable item) are linted against, catching documentation
1499errors early. If there are no lint errors, the doc comments are guaranteed
1500to be visible to documentation tooling, removing a degree of flakiness and
1501unpredictability from the documentation process.
1502
1503- Doc comments are a part of the AST, and so can be produced and consumed by
1504macros, including both `macro_rules!` macros and procedural macros.
1505
1506## Other Rust features
1507
1508### Unsafe code
1509
1510Don’t write unsafe code unless there is no way to implement the same
1511functionality with safe code.
1512
1513If you do have to write unsafe code:
1514
1515
1516- Encapsulate unsafe code in a safe abstraction and isolate it from business
1517logic as much as possible. Ideally, unsafe code should be in a separate
1518crate with few dependencies beyond the standard library.
1519
1520- Add a safety comment starting with `SAFETY:` that explains why the code is
1521correct.
1522
1523- Add a technical justification for unsafe code. Depending on context, this
1524can be a justification for an individual unsafe block or a more general
1525justification that covers an entire file or build target. The justification
1526should answer these questions:
1527
1528
1529- Why is this code not written in an equivalent safe way?
1530
1531- If the reason is performance, are there benchmarks?
1532
1533
1534
1535
1536### No unstable features
1537
1538Don’t use unstable features.
1539
1540Exceptions:
1541
1542
1543- Android Embedded programming may require the
1544use of certain unstable features. While review will be required to enable
1545them (to help search for alternatives), features absolutely required to
1546build an artifact correctly will generally be approved.
1547
1548- Chrome Style arbiters may blanket-approve a
1549small list of features for the entire codebase. Typically, only features
1550that have a clear path to stabilization will be approved.
1551
1552- Fuchsia See guidance
1553here.
1554
1555### Getters and setters
1556
1557Writing and naming getters and setters should follow these guidelines:
1558
1559
1560- `foo()` for a getter that returns `&T`, or `T` by value if `T: Copy`.
1561
1562- `foo_mut()` for a getter that returns a `&mut T`.
1563
1564- `take_foo()` for a getter that “clears” the value (by setting it to `None`
1565or some other default state) and returns the old value.
1566
1567- `set_foo()` for a setter that takes a `T` by value.
1568
1569- `with_foo()` / `with_mut_foo()` for an accessor that operates via a closure
1570(see details below). Such an accessor is invoked as
1571`object.with_foo(|foo| frob(foo))`.
1572
1573- `replace_foo()` for a setter that returns the old value.
1574
1575Examples
1576
1577```rust
1578impl Stuff {
1579 fn foo(&self) -> &Foo { ... }
1580 fn foo_mut(&mut self) -> &mut Foo { ... }
1581
1582 /// Sets "baz" property to `None` and returns the old value.
1583 fn take_baz(&mut self) -> Option<Baz> { ... }
1584
1585 fn set_foo(&mut self, foo: Foo) { ... }
1586
1587 /// Calls `f` with a borrow of the "bar" property.
1588 /// Returns the return value of `f`.
1589 fn with_bar<R>(&self, f: impl FnOnce(&Bar) -> R) -> R { ... }
1590
1591 /// Calls `f` with a mutable borrow of the "bar" property.
1592 /// Returns the return value of `f`.
1593 fn with_mut_bar<R>(&self, f: impl FnOnce(&mut Bar) -> R) -> R { ... }
1594
1595 /// Sets "foo" property to `foo` and returns the old value.
1596 fn replace_foo(&mut self, foo: Foo) -> Foo { ... }
1597}
1598```
1599
1600#### More on accessors that accept closures
1601
1602Accessors that accept a closure (`.with_foo()`) are typically invoked as
1603`object.with_foo(|foo| do_something_with(foo))`. They can be a good choice in
1604the following situations:
1605
1606
1607-
1608 When the property is contained in an interior mutability wrapper (e.g.
1609`Mutex` or `RefCell`). These mechanisms need to constrain access to the
1610property to a scope, and the closure provides this scope. This is usually
1611preferable to directly returning the RAII object that implements the scope
1612(e.g. `MutexGuard<T>`) because the latter would leak an implementation
1613detail.
1614
1615
1616
1617-
1618 When follow-up work or validation is needed after a property is changed and
1619a `set_foo()` accessor cannot be used (for example because the property’s
1620type is expensive to clone or cannot be cloned at all).
1621
1622
1623
1624A `with_foo()` accessor will often allow the closure to return a value and
1625forward it by returning it from `with_foo()`.
1626
1627If you need to provide two closure-accepting accessors, one for read-only access
1628and one for mutable access, it is common to name them `with_foo()` and
1629`with_mut_foo()`. Otherwise, `with_foo()` is often also used for mutating
1630accessors.
1631
1632### Implement expected API sets together
1633
1634If you implement `len()`, also implement `is_empty()`. For context, see Clippy
1635lint
1636`len_without_is_empty`.
1637
1638### Do not access items marked `#[doc(hidden)]` that you don’t own
1639
1640Treat items marked `#[doc(hidden)]` as private. Don’t access them unless you own
1641the code.
1642
1643### Use `const` functions responsibly
1644
1645Mark a public function as `const` only if you expect it to remain `const` in the
1646future (or can commit to helping clients migrate when it changes).
1647
1648Rationale
1649
1650It’s a breaking change to turn a `const` function into a regular function.
1651
1652### Avoid overloading for non-mathematical purposes
1653
1654Use operator overloads for their original mathematical/logical purpose, not just
1655to make the code more concise (as “syntax sugar”).
1656
1657### Apply `#[non_exhaustive]` to publicly-exposed enums
1658
1659If an enum is part of a public API used by other teams, mark it
1660`#[non_exhaustive]`.
1661
1662Exceptions:
1663
1664
1665- The enum will never change. For example:
1666
1667
1668- Enums describing an existing ontology (e.g.,
1669`enum Color { Red, Green, Blue }`).
1670
1671- Enums with two states that could be Booleans (e.g.,
1672`enum Visibility { Visible, Hidden }`)
1673
1674
1675
1676
1677- The enum may change in the future, but you are committed to fixing
1678resulting breakages via an LSC.
1679
1680For context, see Clippy lint
1681`exhaustive_enums`.
1682
1683Rationale
1684
1685Marking an enum `#[non_exhaustive]` forces users to include a wildcard arm
1686(`_ => ...`) in `match` statements. This ensures code continues to compile when
1687new variants are added to the enum later.
1688
1689This rule is primarily important for enums used across team boundaries, because
1690the scope of the breakage could be significant. Enums used only a small number
1691of times can’t create a large breakage and thus may ignore this rule.
1692
1693### Apply `#[non_exhaustive]` to public structs with public fields
1694
1695Structs with public fields that are part of a public API used by other teams
1696should be marked `#[non_exhaustive]`.
1697
1698Exceptions:
1699
1700
1701- The struct fields are unlikely to change, e.g., because they describe an
1702existing ontology (e.g., a Rectangle type) or the reviewer can otherwise be
1703confident that they will not change.
1704
1705- The struct fields may change in the future, but you are committed to
1706fixing resulting breakages via an LSC.
1707
1708- You want to enable your users to use functional record update (FRU) struct
1709initialization syntax (`Person { name: "foo", ..Default::default() }`).
1710
1711Rationale
1712
1713Adding a new field (even a private one) to a struct with all public fields is a
1714breaking change, because callers can no longer name all fields in a struct
1715literal.
1716
1717A `#[non_exhaustive]` struct can’t be constructed with the struct literal
1718syntax, except for the code in the same crate. This allows new private fields to
1719be added without breaking users.
1720
1721This rule is primarily important for structs used across team boundaries,
1722because the scope of the breakage could be significant. Structs used only a
1723small number of times can’t create a large breakage and thus may ignore this
1724rule.
1725
1726### `#[must_use]` on functions
1727
1728Use `#[must_use]` on functions in these cases:
1729
1730
1731-
1732 The caller cannot use the function correctly if they ignore the return
1733value. This includes pure functions (functions without side effects), such
1734as `HashMap::get()`.
1735
1736
1737
1738-
1739 Any function whose return value represents an error or otherwise critical
1740information about the function’s behavior. If the return type is already
1741annotated `#[must_use]` (which is true of `Result`, for example), the
1742function does not need to be annotated `#[must_use]`.
1743
1744
1745
1746### `#[must_use]` on types
1747
1748Use `#[must_use]` on types intended to be returned by functions that would
1749otherwise be annotated `#[must_use]` according to the
1750rules above.
1751
1752Examples:
1753
1754
1755-
1756 The type is an error type (similar to `Result` or `StatusOr`).
1757
1758
1759
1760-
1761 The type represents a lazily evaluated computation. In other words, the
1762function call doesn’t do anything by itself, and the return value needs to
1763be accessed to cause some desired side effect.
1764
1765
1766
1767### Do not run code before `main()`
1768
1769Do not cause code to run before `main()`, for example by using techniques such
1770as the ctor crate.
1771
1772## Implementation concerns
1773
1774### Don’t overuse type inference
1775
1776Add enough explicit types so that someone familiar with the codebase can figure
1777out what the inferred types are.
1778
1779Prefer to add the types to variable declarations, rather than as
1780turbofishes. If
1781the compiler forces you to add a turbofish, it is generally fine to add a `_`
1782inference marker.
1783
1784Specific situations in which you should probably add types:
1785
1786
1787- When calling methods with a generic return type, such as `.into()` or
1788`.parse()`.
1789
1790- For the result of complex iterator chains.
1791
1792### Prefer pattern matching over check-then-unwrap
1793
1794Avoid potentially panicking operations when the input data guarantees they
1795cannot panic. For example, instead of using `Option::unwrap` on a value known to
1796be valid, use pattern matching to prove correctness to the compiler.
1797
1798```rust
1799// Good: The match arm proves to the compiler that `x` is `Some`.
1800// A panic is obviously not possible.
1801if let Some(value) = option {
1802 use_value(value);
1803}
1804```
1805
1806```rust
1807// Bad: Correctness of `unwrap` relies on a runtime check that `option` is `Some`.
1808if option.is_some() {
1809 use_value(option.unwrap());
1810}
1811```
1812
1813### Prefer `expect` over `unwrap`
1814
1815If a panic is necessary because an invariant cannot be expressed in the type
1816system, prefer `expect` over `unwrap` to document the reason.
1817
1818### Don’t omit patterns on `non_exhaustive` enums when matching
1819
1820Prefer to list all enum variants in `match` statements over `non_exhaustive`
1821enums.
1822
1823If you don’t care about specific variants, place them in the wildcard arm. If
1824you only care about specific variants, use an `if let` or a `let … else {}`.
1825
1826Examples:
1827
1828```rust
1829#[non_exhaustive]
1830pub enum Shape {
1831 Circle,
1832 Square,
1833 Triangle,
1834}
1835```
1836
1837```rust
1838fn process_shape(shape: Shape) {
1839 match shape {
1840 Shape::Circle => println!("It's a circle"),
1841 Shape::Square => println!("It's a square"),
1842 // Triangle and any future variants don't require any actions.
1843 Shape::Triangle | _ => {}
1844 }
1845}
1846```
1847
1848```rust
1849fn process_shape(shape: Shape) {
1850 if let Shape::Circle = shape {
1851 println!("It's a circle");
1852 }
1853}
1854```
1855
1856```rust
1857fn process_shape(shape: Shape) {
1858 match shape {
1859 Shape::Circle => println!("It's a circle"),
1860 _ => {}
1861 }
1862}
1863```
1864
1865Exceptions:
1866
1867
1868- You only care about specific variants and `match` is cleaner than
1869`if let`.
1870
1871### Use context strings to clarify assertions
1872
1873While some assertions are self-explanatory, many benefit from additional context
1874that clarifies why an assertion is expected to hold, or what caused it to be
1875violated. Use the optional format string argument for `assert!` to convey this
1876context.
1877
1878You should always consider adding context, but particularly in the following
1879situations:
1880
1881
1882- If you’re thinking of adding a comment to the assertion. Use a format string
1883instead: It has the benefit that it will appear in logs.
1884
1885- If you expect failing assertions to be seen by users. In this case, a
1886human-readable explanation is more helpful than a Rust expression.
1887
1888- If logging a value helps in understanding why the assertion failed.
1889
1890- To clarify whether a failing assertion means that
1891
1892
1893- The client misused an API (i.e., they should change their use of the
1894API), or
1895
1896- The implementation contains a bug (i.e., the client should file a bug
1897report).
1898
1899
1900
1901
1902Examples
1903
1904Explaining why an assertion should hold
1905
1906```rust
1907assert!(
1908 values.is_sorted(),
1909 "`values` is populated from a `PriorityQueue`, so we expect it to be sorted"
1910 );
1911```
1912
1913Logging a value to clarify why the assertion failed
1914
1915```rust
1916assert!(refund > 0, "Refund must be positive, got {refund:?}");
1917```
1918
1919Flagging misuse of an API
1920
1921```rust
1922impl Database {
1923 ...
1924
1925 fn execute_query(&self, query: &str) {
1926 assert!(self.stream.is_some(), "Call connect() before executing queries");
1927 }
1928
1929 ...
1930}
1931```
1932
1933Don’t use the context string merely to repeat the condition
1934
1935```rust
1936assert!(values.is_sorted(), "values should always be sorted");
1937```
1938
1939### Don’t use iterator combinator chains when direct iteration is clearer
1940
1941Avoid using combinator chains in ways that hurt readability. Specifically:
1942
1943
1944- Avoid long and complex combinator chains.
1945
1946- Don’t construct combinator chains in the header of a `for` loop. Instead,
1947assign the combinator chain to a variable, then consume that variable in the
1948`for` loop.
1949
1950- Avoid `Iterator::for_each` unless you’re convinced you have a good reason. A
1951`for` loop is usually easier to read.
1952
1953Combinators are preferable for shorter chains and for cases where the
1954combinator itself provides a lot of logic that would otherwise have to be
1955written out in the corresponding `for` loop.
1956
1957Examples
1958
1959Complex combinator chains
1960
1961Here’s an example of a combinator chain that is hard to read because it involves
1962conditionals and mutates external state:
1963
1964```rust
1965let mut error_count = 0;
1966let _processed_items: Vec<_> = items
1967 .into_iter()
1968 .map(transformation_that_may_fail)
1969 .map(|result| {
1970 if result.is_err() {
1971 error_count += 1;
1972 }
1973 result
1974 })
1975 .filter_map(Result::ok)
1976 .collect();
1977```
1978
1979The corresponding `for` loop is easier to read:
1980
1981```rust
1982let mut error_count = 0;
1983let mut processed_items = Vec::with_capacity(items.len());
1984
1985for item in items {
1986 match transformation_that_may_fail(item) {
1987 Ok(val) => processed_items.push(val),
1988 Err(_) => error_count += 1,
1989 }
1990}
1991```
1992
1993Combinator chains in for loops
1994
1995Avoid constructing a combinator chain in the header of a `for` loop:
1996
1997```rust
1998for bug in bug_descriptions
1999 .iter()
2000 .filter_map(|description| parse_bug_description(description).ok())
2001 .filter(|bug| bug.priority <= Priority::P1)
2002{
2003 assign_bug(bug);
2004}
2005```
2006
2007Instead, assign the combinator chain to a variable. This reduces clutter, and
2008the variable name documents what the combinator chain does:
2009
2010```rust
2011let urgent_bugs = bug_descriptions
2012 .iter()
2013 .filter_map(|description| parse_bug_description(description).ok())
2014 .filter(|bug| bug.priority <= Priority::P1);
2015
2016for bug in urgent_bugs {
2017 assign_bug(bug);
2018}
2019```
2020
2021When to prefer a combinator chain
2022
2023Here’s an example where a combinator chain is preferable:
2024
2025```rust
2026let threshold_exceeded = values.iter().any(|&v| v > threshold);
2027```
2028
2029The corresponding for loop is harder to read and reinvents the logic contained
2030in `any()`:
2031
2032```rust
2033let mut threshold_exceeded = false;
2034for v in values {
2035 if v > threshold {
2036 threshold_exceeded = true;
2037 break;
2038 }
2039}
2040```
2041
2042### Don’t call `panic::catch_unwind`
2043
2044Use of `panic::catch_unwind` is prohibited in first-party Rust code.
2045
2046Exceptions:
2047
2048
2049- It is acceptable as a defense in depth mechanism as long as it is never
2050relied upon for any properties. A codebase that is already attempting to
2051avoid panics may choose to wrap critical entry points with a `catch_unwind`
2052recovery mechanism just in case a panic slips through. Code authors must
2053convince the reviewer that the codebase is doing most of what it can to
2054avoid panics. This exception only applies to code that has the possibility
2055of being run with `panic=unwind` (so this does not apply to
2056Chrome, Android,
2057Fuchsia).
2058
2059Rationale
2060
2061Rust code may be used in many environments, and `panic::catch_unwind` will only
2062function correctly in environments with `panic=unwind`. While the final panic
2063disposition of prod binaries has not yet been determined, Chrome, Android, and
2064Fuchsia all require `panic=abort`.
2065
2066### Prefer `format!` / `write!` for concatenation and substitution
2067
2068Prefer `format!()` and `write!()` to other alternatives in the following
2069situations:
2070
2071
2072- To concatenate more than two strings. For example, use
2073`format!("{a}{b}{c}")` instead of `a + b + c`.
2074
2075- To perform substitutions on a literal string (instead of using
2076`str::replace`).
2077
2078Rationale
2079
2080
2081- `format!` / `write!` require fewer allocations than concatenating strings
2082using `+`.
2083
2084- Prefer standard format strings to inventing your own templating syntax.
2085
2086## Use the right per-codebase test framework
2087
2088Most codebases use their own specific test framework rather than `#[test]`.
2089
2090
2091-
2092 Chrome Use
2093rust_gtest_interop.
2094This makes it possible to integrate Rust tests into C++ test binaries.
2095
2096
2097
2098-
2099 Fuchsia Use `#[fuchsia::test]`. See
2100here
2101for more details.
2102
2103
2104
2105
2106
2107 This site is open source. Improve this page.
Added skills/google-rust-style/LICENSE skills/google-rust-style/LICENSE +26 −0 View skills/google-rust-style/LICENSE
@@ -0,0 +1,26 @@
1MIT License
2
3Copyright (c) 2026 srk
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in all
13copies or substantial portions of the Software.
14
15Note: the distilled rules in this repository are derived from the Google Rust
16Style Guide (https://google.github.io/styleguide/rustguide.html), (c) Google,
17licensed under CC BY 3.0. The full extracted source text in
18references/source-text.md remains (c) Google.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26SOFTWARE.
Added skills/google-rust-style/README.md skills/google-rust-style/README.md +58 −0 View skills/google-rust-style/README.md
@@ -0,0 +1,58 @@
1# google-rust-style
2
3将 [Google Rust Style Guide](https://google.github.io/styleguide/rustguide.html) 提炼成的 **Agent Skill**——写代码、做 code review 时由 AI 编程助手自动加载,按谷歌规范约束 Rust 的 API 设计、代码组织、命名、文档与实现细节。
4
5> An Agent Skill that distills Google's Rust Style Guide for AI coding agents. Works with any tool that supports the open Agent Skills format (a folder with `SKILL.md`), including ZCode, DSH (DeepSeek Harness), OpenCode and Codex.
6
7## 背景
8
9Google 对 "style" 的定义不止代码格式,还涵盖 API 与实现设计。本仓库把整份指南做成渐进式加载的技能:触发时只载入速查与索引,按具体任务再读分主题的参考文件,另附原文机器提取稿用于核对。
10
11提炼时保留了指南的三个关键机制:
12
13- 每条规则的**例外情况**(例外也是规则的一部分)
14- `[chrome]` / `[Fuchsia]` 专属规则标记(只适用于对应代码库,通用项目不套用)
15- "库代码强制、应用代码建议"的执行总纲
16
17## 文件结构
18
19| 文件 | 内容 |
20|---|---|
21| `SKILL.md` | 触发描述、库/应用代码定位、高频规则速查、主题索引 |
22| `references/organization-and-formatting.md` | crate 划分、模块/文件布局、imports 规则、rustfmt 配置 |
23| `references/api-design.md` | 函数输入输出、错误上报、trait 设计、getter/setter、`#[non_exhaustive]`、`#[must_use]`、unsafe |
24| `references/naming-and-documentation.md` | 命名(`as_`/`to_`/`into_`、构造器、生命周期)与文档注释规范 |
25| `references/implementation.md` | `Rc`/`Arc`、clone、模式匹配、断言上下文、迭代器链、测试框架 |
26| `references/source-text.md` | 原指南全文机器提取稿(英文,核对用) |
27
28## 安装
29
30适用于支持 Agent Skills 目录约定(技能目录 + `SKILL.md`)的工具:
31
32| 工具 | 技能目录 |
33|---|---|
34| ZCode | `~/.zcode/skills/` 或 `~/.agents/skills/` |
35| DSH (DeepSeek Harness) | `~/.agents/skills/`(放入后重启 dsh) |
36| OpenCode | `~/.config/opencode/skills/`(全局)或 `.opencode/skills/`(项目) |
37| Codex | `~/.codex/skills/` |
38
39```bash
40git clone https://github.com/LOWRUI/google-rust-style.git ~/.agents/skills/google-rust-style
41```
42
43Windows PowerShell:
44
45```powershell
46git clone https://github.com/LOWRUI/google-rust-style.git $env:USERPROFILE\.agents\skills\google-rust-style
47```
48
49安装后无需手动调用:用 Rust 写代码、review、讨论 rustfmt / clippy / 谷歌 Rust 规范时自动触发。
50
51## 来源与许可
52
53- 规则内容提炼、转述自 [Google Rust Style Guide](https://google.github.io/styleguide/rustguide.html)。原指南内容 © Google,以 [CC BY 3.0](https://creativecommons.org/licenses/by/3.0/) 发布;`references/source-text.md` 为其机器提取稿,版权归 Google,仅随技能作核对用途。
54- 本仓库的提炼与撰写部分以 [MIT License](LICENSE) 发布。
55
56## 更新说明
57
58基于 2026-10 抓取的指南版本提炼。原指南更新后欢迎提 issue / PR 同步。
Added skills/google-rust-style/SKILL.md skills/google-rust-style/SKILL.md +55 −0 View skills/google-rust-style/SKILL.md
@@ -0,0 +1,55 @@
1---
2name: google-rust-style
3description: 按 Google Rust 风格指南(https://google.github.io/styleguide/rustguide.html)编写、审查与重构 Rust 代码:涵盖 API 设计、代码组织、命名、文档与实现规范。凡是用 Rust 写代码、做 code review、讨论或检查 Rust 风格、rustfmt、clippy、Rust API 设计,或提到 Google Rust Style Guide / 谷歌 Rust 规范时都应使用——即使没有明说"风格"二字。
4---
5
6# Google Rust 风格指南
7
8提炼自 https://google.github.io/styleguide/rustguide.html(2026-10 抓取版本,原文全文见 references/source-text.md)。Google 对 "style" 的定义不止格式,还包括 API 设计与实现设计规范。
9
10## 定位与优先级
11
121. **先公共规范**:官方 Rust Style Guide(格式规则大部分由 rustfmt 自动执行)+ Rust API Guidelines。本指南在其上叠加 Google 特有规则,冲突时 Google 规则优先。
132. **库代码 vs 应用代码**:API 设计类规则对库代码(供其他项目复用、解决较通用问题)是强制要求;对应用代码(单一程序内部、解决特定问题)是强烈建议——应用代码优先简单直接,避免过早泛化和抽象。指南原文多处按此区分(如返回 `Vec` 还是迭代器、参数收切片还是迭代器)。
143. **[chrome] / [Fuchsia] 标记**:带此标记的规则只适用于 Chromium / Fuchsia 代码库,通用 Rust 项目不要套用。参考文件中已保留标记。
154. **指南目标**:可读性与可维护性优先于书写便利;规则应利于自动化与大规模变更(LSC)、与更广 Rust 生态一致、确有实际收益,并减少无谓的风格争论。适用范围:Android、Chromium 等代码库各自决定执行严格程度。
16
17## 怎么用
18
19- **写代码 / 设计 API 前**:按下方主题索引读对应参考文件,不要只凭速查表设计关键 API。
20- **review / 检查既有代码**:按主题索引定位规则逐条对照;指出问题时给出规则名称与出处文件。
21- **格式问题**:交给 rustfmt(推荐配置见 organization-and-formatting.md),不要手工调格式;clippy 覆盖了本指南多条规则(borrowed_box、ptr_arg、should_implement_trait、new_without_default、len_without_is_empty、wrong_self_convention、exhaustive_enums 等),修 clippy 警告通常就是在遵守本指南。
22- **查原文**:浓缩规则未覆盖或存疑时,读 references/source-text.md(原文机器提取,英文)核对。
23
24## 高频规则速查
25
26完整规则、例外与代码示例见参考文件。最常出现的判定:
27
28- 参数借用"剥到底":`&T` 不用 `&Box<T>`,`&[T]` 不用 `&Vec<T>`,`&str` 不用 `&String`,`Option<&T>` 不用 `&Option<T>`。
29- 默认唯一所有权:避免 `Rc`/`Arc`(除非替代结构复杂到不合理);`.clone()` 用于真正需要深拷贝时,不当借用的替代品。
30- 错误上报三分法:失败原因显而易见用 `Option`;调用方需要上下文才能恢复用 `Result`;bug 与违反不变量用 `panic!`。
31- `expect` 优于 `unwrap`;已知合法的值用模式匹配(`if let Some(v) = …`)而不是 check-then-unwrap。
32- 禁用 glob imports(例外有限);一条 `use` 只从一个模块导入;trait 导入尽量放函数体内;顶层函数调用带模块名(`mem::transmute(y)`),类型名则导入后不加限定(用 `Regex` 不用 `regex::Regex`)。
33- API 参数语义不明显时用 `enum` 不用 `bool`。
34- 跨团队公开的 enum、含公开字段的 struct 加 `#[non_exhaustive]`(例外:永不变更的稳定本体、需要用户使用 FRU 语法等)。
35- 命名:构造器 `new()` / `new_with_foo()`、返回 `Result` 用 `try_new()`、值到值转换 `from_foo()` 配 `From` 实现;getter/setter 用 `foo()` / `foo_mut()` / `take_foo()` / `set_foo()` / `with_foo()` / `replace_foo()`;扩展 trait 名以 `Ext` 结尾。
36- unsafe 必须有 `SAFETY:` 注释和技术理由,并封装在安全抽象里;`panic::catch_unwind` 禁用;不用 unstable 特性。
37- 文档注释:公开 API 必须有;`///` 文档化条目、`//!` 模块级、`//` 实现注释,鼓励混用;不解释语言基础、不简单复述函数名。
38- 长迭代器链、在 `for` 头部构造链 → 先赋给具名变量再迭代,或改写为 `for` 循环;少用 `Iterator::for_each`。
39- 拼接超过两段字符串、对字面量做替换:用 `format!` / `write!`。
40
41## 主题索引
42
43| 主题 | 参考文件 |
44|---|---|
45| crate 大小与拆分、文件/模块布局与命名、imports(glob、use 粒度、trait 导入作用域、限定规则)、rustfmt 配置与 `#[rustfmt::skip]` | references/organization-and-formatting.md |
46| 函数参数与返回值(借用形态、迭代器 vs 集合、Into)、错误上报、newtype、trait 设计与选择、泛型 vs dyn、并发、宏的取舍、getter/setter、`#[non_exhaustive]`、`#[must_use]`、unsafe、const fn、运算符重载 | references/api-design.md |
47| 方法前缀(as_/to_/into_)、生命周期与泛型参数命名、构造函数命名、缩写、文档注释规范 | references/naming-and-documentation.md |
48| Rc/Arc、clone 与借用、类型推断、模式匹配、assert 上下文、迭代器链 vs for、catch_unwind、format!、测试框架 | references/implementation.md |
49| 原文全文(机器提取,英文,用于核对) | references/source-text.md |
50
51## 执行注意
52
53- 规则的例外也是规则:应用任何规则前确认不在例外情形里,参考文件逐条保留了原文例外。
54- 与项目已有约定冲突时(rustfmt.toml、现有代码风格、crate 结构),先说明差异再动手,不要静默修改项目配置。
55- 本指南不替代 rustfmt / clippy:能自动化的交给工具,人工与模型只处理工具管不到的设计问题。