├── .github └── workflows │ └── ci.yml ├── .gitignore ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── book.toml ├── language.js └── src ├── README.md ├── SUMMARY.md ├── advice.md ├── cargo.md ├── expressions.md ├── items.md ├── nightly.md ├── principles.md ├── statements.md └── types.md /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | test: 6 | name: Test 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@main 10 | - name: Update rustup 11 | run: rustup self update 12 | - name: Install Rust 13 | run: | 14 | rustup set profile minimal 15 | rustup toolchain install nightly -c rust-docs 16 | rustup default nightly 17 | - name: Install mdbook 18 | run: | 19 | mkdir bin 20 | curl -sSL https://github.com/rust-lang/mdBook/releases/download/v0.4.15/mdbook-v0.4.15-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=bin 21 | echo "$(pwd)/bin" >> ${GITHUB_PATH} 22 | echo "$(pwd)/bin" >> $GITHUB_PATH 23 | - name: Report versions 24 | run: | 25 | rustup --version 26 | rustc -Vv 27 | mdbook --version 28 | - name: Run tests 29 | run: mdbook test 30 | - name: Build HTML 31 | run: mdbook build 32 | 33 | deploy: 34 | if: ${{ github.ref == 'refs/heads/main' }} 35 | name: Deploy 36 | runs-on: ubuntu-latest 37 | needs: test 38 | steps: 39 | - name: Deploy to server 40 | uses: appleboy/ssh-action@master 41 | with: 42 | host: ${{ secrets.SSH_HOST }} 43 | username: ${{ secrets.SSH_USERNAME }} 44 | key: ${{ secrets.SSH_KEY }} 45 | port: ${{ secrets.SSH_PORT }} 46 | script: | 47 | ./tools/rust-deploy/update-cn.sh >/dev/null 2>&1 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | book 2 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Rust 中文翻译项目组 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rust 语言风格指南 2 | 3 | ![Build Status](https://github.com/rust-lang-cn/style-guide-cn/workflows/CI/badge.svg) 4 | [![LICENSE-MIT](https://img.shields.io/badge/license-MIT-green)](https://raw.githubusercontent.com/rust-lang-cn/style-guide-cn/master/LICENSE-MIT) 5 | [![LICENSE-APACHE](https://img.shields.io/badge/license-Apache%202-blue)](https://raw.githubusercontent.com/rust-lang-cn/style-guide-cn/master/LICENSE-APACHE) 6 | [![GitHub last commit](https://img.shields.io/github/last-commit/rust-lang-cn/style-guide-cn?color=gold)](https://github.com/rust-lang-cn/style-guide-cn/commits/master) 7 | [![GitHub contributors](https://img.shields.io/github/contributors/rust-lang-cn/style-guide-cn?color=pink)](https://github.com/rust-lang-cn/style-guide-cn/graphs/contributors) 8 | ![Locatized 100%](https://img.shields.io/badge/localized-100%25-purple) 9 | [![rustwiki.org](https://img.shields.io/website?up_message=rustwiki.org&url=https%3A%2F%2Frustwiki.org)](https://rustwiki.org) 10 | 11 | > The Chinese Translation of [The Rust Style Guide][style-guide-en] 12 | > 13 | > - 首次于 2023-07-31 翻译完全部内容,欢迎纠正——最后更新时间 2023-07-31。 14 | > - 期待更多朋友加入 [Rust 中文翻译项目组](https://github.com/rust-lang-cn),协助我们,一起更新完善中文版,感激不尽! 15 | 16 | 这是《Rust 语言风格指南》中文版,翻译自 [Rust 源码中的《The Rust Style Guide》][style-guide-src]。 17 | 18 | 在线版可在本组织官网上阅读,包括[全球站点][style-guide-cn]或[国内站点][style-guide-cn-zh](**均支持同一页面中英双语切换**),或者在 Rust 官网上[阅读英文版][style-guide-en]。 19 | 20 | [style-guide-src]: https://github.com/rust-lang/rust/tree/master/src/doc/style-guide 21 | [style-guide-cn]: https://rustwiki.org/zh-CN/style-guide/ 22 | [style-guide-cn-zh]: https://www.rustwiki.org.cn/zh-CN/style-guide/ 23 | [style-guide-en]: https://doc.rust-lang.org/style-guide/ 24 | 25 | ## 构建 26 | 27 | 构建之前请先安装 `mdBook` 工具。 28 | 29 | 从 GitHub 下载仓库并构建: 30 | 31 | ```sh 32 | $ git clone https://github.com/rust-lang-cn/style-guide-cn.git 33 | $ cd style-guide-cn 34 | $ mdbook serve 35 | ``` 36 | 37 | 然后就可以在浏览器上访问 `http://localhost:3000` 来查看文档内容了。 38 | 39 | 要生成本地图书,使用以下命令: 40 | 41 | ```sh 42 | $ mdbook build 43 | ``` 44 | 45 | 即可在当前仓库目录下生存一个 `book` 子目录,可找到相应的 HTML 文件。 46 | 47 | ## 许可协议 48 | 49 | 《Rust 语言风格指南》(中文版与英文版 *The Rust Style Guide* 均) 使用以下两种协议的任一种进行授权: 50 | 51 | - Apache 2.0 授权协议,([LICENSE-APACHE](LICENSE-APACHE) 或 http://www.apache.org/licenses/LICENSE-2.0) 52 | - MIT 授权协议 ([LICENSE-MIT](LICENSE-MIT) 或 http://opensource.org/licenses/MIT) 53 | 54 | 可以根据自己选择来定。 55 | 56 | 除非您有另外说明,否则您在本仓库提交的任何贡献均按上述方式进行双重许可授权,就如 Apache 2.0 协议所规定那样,而无需附加任何其他条款或条件。 57 | -------------------------------------------------------------------------------- /book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | title = "Rust 语言风格指南 中文版" 3 | author = "The Rust Style Team" 4 | translator = "Rust 中文翻译项目组,Rust 中文社区" 5 | multilingual = false 6 | language = "zh-CN" 7 | src = "src" 8 | 9 | [output.html] 10 | additional-js = ["language.js"] 11 | git-repository-url = "https://github.com/rust-lang-cn/style-guide-cn" 12 | edit-url-template = "https://github.com/rust-lang-cn/style-guide-cn/edit/main/{path}" 13 | -------------------------------------------------------------------------------- /language.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | var url = window.location.href; 3 | var host = window.location.host; 4 | var home_url = window.location.protocol + '//' + window.location.host; 5 | 6 | var search = { 7 | en: "/en/", 8 | zh_CN: "/zh-CN/" 9 | } 10 | 11 | var replaceWith = { 12 | en: "/zh-CN/", 13 | zh_CN: "/en/" 14 | } 15 | 16 | var link = ""; 17 | var word = ""; 18 | var home = "Home"; 19 | var lang = "zh-CN"; 20 | var changeLang = "切换到英语"; 21 | 22 | if (url.indexOf(search.en) != -1 && url.indexOf(search.en) === (url.indexOf(host) + host.length)) { 23 | link = url.replace(search.en, replaceWith.en); 24 | word = "简体中文"; 25 | lang = "en"; 26 | changeLang = "Switch to Chinese" 27 | } else if (url.indexOf(search.zh_CN) != -1 && url.indexOf(search.zh_CN) === (url.indexOf(host) + host.length)) { 28 | link = url.replace(search.zh_CN, replaceWith.zh_CN); 29 | word = "English"; 30 | home = "首页"; 31 | } 32 | 33 | var edit_id = document.getElementById("git-edit-button"); 34 | if (edit_id != null && edit_id.parentNode != null) { 35 | edit_id.parentNode.target = "_blank"; 36 | if (lang != "en") { 37 | edit_id.parentNode.title = "报告错误或改进本页翻译"; 38 | } 39 | } 40 | 41 | var home_node = ''; 42 | if (window.location.protocol == 'http:' || window.location.protocol == 'https:') { 43 | home_node = ''; 44 | } 45 | var lang_node = ''; 46 | if (link != '') { 47 | lang_node = ' ' + word + ''; 48 | } 49 | var insertNode = document.getElementsByClassName('right-buttons'); 50 | if (insertNode.length > 0) { 51 | var html = insertNode[0].innerHTML; 52 | insertNode[0].innerHTML = home_node + html + lang_node; 53 | } 54 | })() 55 | -------------------------------------------------------------------------------- /src/README.md: -------------------------------------------------------------------------------- 1 | # Rust 语言风格指南 2 | 3 | ## 动机——为什么要使用格式化工具? 4 | 5 | 格式化代码是一项耗时耗力的机械性工作。如果使用自动格式化工具,开发者就可以从这项工作中解脱出来,专注于更重要的事情。 6 | 7 | 此外,通过坚持使用既定的风格指南(如本指南),开发者无需制定特别的风格规则,也无需与其他开发者争论应使用何种样式规则,从而节省了时间、沟通成本和精神耗损。 8 | 9 | 人类通过模式匹配来理解信息。通过确保所有 Rust 代码具有相似的格式,就能减少理解新项目所需的脑力劳动,从而降低新开发人员的入门门槛。 10 | 11 | 因此,使用格式化工具(如 `rustfmt`)可以提高工作效率,而使用社区一致的格式规约(通常是使用格式化工具的默认设置)则会带来更大的好处。 12 | 13 | ## 默认 Rust 风格 14 | 15 | 《Rust 语言风格指南》定义了默认 Rust 风格,并**建议**开发者和工具遵循默认 Rust 样式。`rustfmt` 等工具使用此风格指南作为默认风格的参考。本风格指南中的所有内容,无论是否使用“必须”等语言或“插入空格......”或“在......后换行”等命令式语气,都是指默认样式。 16 | 17 | 这不应被解释为禁止开发人员遵循非默认样式,或禁止工具添加任何特定的配置选项。 18 | 19 | ## 格式约定 20 | 21 | ### 缩进和行宽 22 | 23 | - 使用空格,而不是制表符。 24 | - 每级缩进必须是 4 个空格(也就是说,字符串字面量和注释之外的所有缩进空格数都必须是 4 的倍数)。 25 | - 一行的最大宽度为 100 个字符。 26 | 27 | #### 块缩进 28 | 29 | 与视觉化缩进(visual indent)相比,更倾向于分块缩进: 30 | 31 | ```rust,ignore 32 | // 块缩进 33 | a_function_call( 34 | foo, 35 | bar, 36 | ); 37 | 38 | // 视觉化缩进 39 | a_function_call(foo, 40 | bar); 41 | ``` 42 | 43 | 这样做的差异就会变小(例如,在上例中重命名了`a_function_call`),向右移动的情况也会减少。 44 | 45 | ### 尾逗号 46 | 47 | 在任何类型的逗号分隔列表中,如果后面有换行符,请使用尾逗号: 48 | 49 | ```rust,ignore 50 | function_call( 51 | argument, 52 | another_argument, 53 | ); 54 | 55 | let array = [ 56 | element, 57 | another_element, 58 | yet_another_element, 59 | ]; 60 | ``` 61 | 62 | 这使得移动代码(例如通过复制和粘贴)变得更容易,并使差异更小,因为添加或删除项目不需要修改另一行来添加或删除逗号。 63 | 64 | ### 空行 65 | 66 | 不用空行或一个空行(即 1 或 2 个换行符)分隔程序项和语句。例如: 67 | 68 | ```rust,ignore 69 | fn foo() { 70 | let x = ...; 71 | 72 | let y = ...; 73 | let z = ...; 74 | } 75 | 76 | fn bar() {} 77 | fn baz() {} 78 | ``` 79 | 80 | ### [模块级别的程序序项](items.md) 81 | ### [语句](statements.md) 82 | ### [表达式](expressions.md) 83 | ### [类型](types.md) 84 | 85 | ### 注释 86 | 87 | 以下关于注释的指导原则仅为建议,机器格式化工具可能会跳过注释格式化。 88 | 89 | 行注释 (`//`) 优先于块注释 (`/* ... */`)。 90 | 91 | 使用行注释时,在开头符号后留一个空格。 92 | 93 | 使用单行块注释时,在开头符号后和结尾符号前各留一个空格。对于多行块注释,在开头符号后加一个换行符,在结尾符号前加一个换行符。 94 | 95 | 注释最好独立成行。如果注释紧跟代码,则在注释前空格一个。如果块注释出现在行内,则使用周围的空格,就像使用标识符或关键字一样。不要在注释后或多行注释中任何一行的末尾使用拖尾空格。例如: 96 | 97 | ```rust,ignore 98 | // 程序项中的注释。 99 | struct Foo { ... } 100 | 101 | fn foo() {} // 在一个项后的注释。 102 | 103 | pub fn foo(/* 在参数前的注释 */ x: T) {...} 104 | ``` 105 | 106 | 注释通常应是完整的句子。英文的注释开头用大写字母,结尾用句点(`.`)(译注:若是使用中文注释,则换成中文标点符号)。内联块注释可视为不带标点符号的注释。 107 | 108 | 完全是注释的源文件行长度应限制在 80 个字符以内(包括注释符号,但不包括缩进),或该行的最大宽度(包括注释符号和缩进),以较小者为准: 109 | 110 | ```rust,ignore 111 | // This comment goes up to the ................................. 80 char margin. 112 | // 该注释的边距为 ............................. 80 字符。 113 | 114 | { 115 | // This comment is .............................................. 80 chars wide. 116 | // 此注释宽 ............................................................. 80 字符。 117 | } 118 | 119 | { 120 | { 121 | { 122 | { 123 | { 124 | { 125 | // This comment is limited by the ......................... 100 char margin. 126 | // 此注释受 ................................................ 100 字符边距的限制。 127 | } 128 | } 129 | } 130 | } 131 | } 132 | } 133 | ``` 134 | 135 | #### 文档注释 136 | 137 | 优先使用行注释 (`///`) 而不是块注释 (`/** ... */`)。 138 | 139 | 优先使用外层文档注释(`///` 或 `/** ... */`),仅使用内层文档注释(`//!` 和 `/*! ... */`)编写模块级或 crate 块级的文档。 140 | 141 | 将文档注释放在属性之前。 142 | 143 | ### 属性 144 | 145 | 每个属性放在单独一行,跟程序项保持一致的缩进。如果是内部属性 (`#!`),则缩进到程序项内部的位置。尽可能使用外属性。 146 | 147 | 对于带有参数列表的属性,格式应与函数类似。 148 | 149 | ```rust,ignore 150 | #[repr(C)] 151 | #[foo(foo, bar)] 152 | #[long_multi_line_attribute( 153 | split, 154 | across, 155 | lines, 156 | )] 157 | struct CRepr { 158 | #![repr(C)] 159 | x: f32, 160 | y: f32, 161 | } 162 | ``` 163 | 164 | 对于带有等号的属性,在 `=` 前后各加一个空格,如 `#[foo = 42]`。 165 | 166 | 必须只有一个 `derive` 属性。工具的作者们要注意:如果将多个 `derive` 属性合并为一个属性,通常必须保留派生名称的顺序,以保证正确性: `#[derive(Foo)] #[derive(Bar)] struct Baz;` 必须格式化为 `#[derive(Foo, Bar)] struct Baz;`。 167 | 168 | For attributes with an equal sign, put a single space before and after the `=`, 169 | e.g., `#[foo = 42]`. 170 | 171 | ### **简短**程序项 172 | 173 | 在本指南的许多地方,我们指定的格式取决于代码结构的**简短**。例如,单行结构文字与多行结构文字: 174 | 175 | ```rust,ignore 176 | // 正常格式化 177 | Foo { 178 | f1: an_expression, 179 | f2: another_expression(), 180 | } 181 | 182 | // “简短”格式化 183 | Foo { f1, f2 } 184 | ``` 185 | 186 | 我们让各个工具自行决定“简短”的确切含义。特别是,在不同的情况下,工具可以自由使用不同的定义。 187 | 188 | 一些合适的启发式方法是程序项的大小(以字符为单位)或程序项的复杂程度(例如,所有组件必须是简单的名称,而不是更复杂的子表达式)。有关合适的启发式方法的更多讨论,请参考[此讨论问题](https://github.com/rust-lang-nursery/fmt-rfcs/issues/47)。 189 | 190 | ## [非格式化约定](advice.md) 191 | 192 | ## [Cargo.toml 的约定](cargo.md) 193 | 194 | ## [决定这些准则的原则](principles.md) 195 | -------------------------------------------------------------------------------- /src/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | [简介](README.md) 4 | 5 | - [程序项](items.md) 6 | - [语句](statements.md) 7 | - [表达式](expressions.md) 8 | - [类型和约束](types.md) 9 | - [其他风格建议](advice.md) 10 | - [`Cargo.toml` 的约定](cargo.md) 11 | - [指导原则和基本原理](principles.md) 12 | - [开发版特定语法](nightly.md) 13 | -------------------------------------------------------------------------------- /src/advice.md: -------------------------------------------------------------------------------- 1 | # 其他风格建议 2 | 3 | ## 表达式 4 | 5 | 尽可能使用 Rust 面向表达式的特性; 6 | 7 | ```rust,ignore 8 | // 使用 9 | let x = if y { 1 } else { 0 }; 10 | // 不使用 11 | let x; 12 | if y { 13 | x = 1; 14 | } else { 15 | x = 0; 16 | } 17 | ``` 18 | 19 | ## 命名规范 20 | 21 | - 类型应为首字母大写的驼峰命名法(`UpperCamelCase`), 22 | - 枚举变量应为首字母大写的驼峰命名法(`UpperCamelCase`), 23 | - 结构体字段应使用纯小写下划线命名法(`snake_case`), 24 | - 函数和方法名称应使用纯小写下划线命名法(`snake_case`), 25 | - 局部变量应为纯小写下划线命名法(`snake_case`), 26 | - 宏名称应为纯小写下划线命名法(`snake_case`), 27 | - 常量(常量和不可变静态)应使用纯大写下划线命名(`SCREAMING_SNAKE_CASE`) 28 | - 当名称是保留字(如 `crate`)而禁止使用时,要么使用原始标识符(`r#crate`),要么使用尾部下划线(`crate_`)——不要拼错单词 (`krate`)。 29 | 30 | ### 模块 31 | 32 | 尽可能避免使用 `#[path]` 标注。 33 | -------------------------------------------------------------------------------- /src/cargo.md: -------------------------------------------------------------------------------- 1 | # `Cargo.toml` 的约定 2 | 3 | ## 格式约定 4 | 5 | 使用与 Rust 代码相同的行宽和缩进。 6 | 7 | 在一个表块的最后一个键值对与下一表块的标题之间空一行。在表块标题和该表块中的键值对之间,或同一表块中的键值对之间,不要加空行。 8 | 9 | 除 `[package]` 表块外,按字母顺序排列各部分中的键名。将 `[package]` 表块放在文件的顶部;将 `name` 和 `version` 键按顺序放在该表块的顶部,接着除 `description` 外的其余键按字母顺序排列,最后是该表块的末尾的 `description`。 10 | 11 | 任何标准键名都不要使用引号,使用裸键。只有名称需要引号的非标准键才使用引号,并尽可能避免引入此类键名。详情请参见 [TOML 规范](https://toml.io/cn/v1.0.0#键名)。 12 | 13 | 在键和值之间的 `=` 前后各留一个空格。不要缩进任何键名;所有键名都从一行的开头开始。 14 | 15 | 对于包含多行的字符串值,如 crate 说明,应使用多行字符串(而不是换行符)。 16 | 17 | 对于数组值(如特性列表),如果合适,可将整个列表与键放在同一行。否则,使用分块缩进:在开头的方括号后加一个换行符,每个项缩进一级,每个项(包括最后一个项)后加一个逗号,最后一个项后将结尾的方括号放在一行的开头。 18 | 19 | 对于数组值(如特征列表),如果合适,可将整个列表与键放在同一行。否则,使用分块缩进:在开头的方括号后加一个换行符,每个项目缩进一级,每个项目(包括最后一个项目)后加一个逗号,最后一个项目后将结尾的方括号放在一行的开头。 20 | 21 | ```rust,ignore 22 | some_feature = [ 23 | "another_feature", 24 | "yet_another_feature", 25 | "some_dependency?/some_feature", 26 | ] 27 | ``` 28 | 29 | 对于表值,例如带有路径的 crate 依赖关系,如果合适的话,使用大括号和逗号将整个表写在与键相同的行上。如果整个表格不能与关键字写在同一行,则应使用键值对将其分隔成一个单独的部分: 30 | 31 | ```toml 32 | [dependencies] 33 | crate1 = { path = "crate1", version = "1.2.3" } 34 | 35 | [dependencies.extremely_long_crate_name_goes_here] 36 | path = "extremely_long_path_name_goes_right_here" 37 | version = "4.5.6" 38 | ``` 39 | 40 | ## 元数据约定 41 | 42 | 作者列表(若有的话)应由字符串组成,每个字符串包含一个作者姓名,后面是置于尖括号内的电子邮件地址: `Full Name 43 | `。不应包含空电子邮件地址或没有电子邮件地址的姓名。(作者列表中也可以包含没有相关姓名的邮件列表地址)。 44 | 45 | 许可证字段必须包含有效的 [SPDX 表达式](https://spdx.org/spdx-specification-21-web-version#h.jxpfx0ykyb60),并使用有效的 [SPDX 许可证名称](https://spdx.org/licenses/)。(作为例外,根据普遍惯例,许可证字段可以使用 `/` 代替 ` OR `,例如 `MIT/Apache-2.0`)。 46 | 47 | 主页字段(若有的话)必须包含一个单独的 URL,包括协议(如 `https://example.org/`,而不只是 `example.org`)。 48 | 49 | 在描述字段中,按 80 列对文本进行换行。不要以 crate 的名称作为描述字段的开头(例如 "cratename is a ...");只需描述 crate 本身。如果提供的是多句描述,第一句应单独成行并概括 crate,就像电子邮件或提交信息的主题一样;随后的句子可以更详细地描述 crate。 50 | -------------------------------------------------------------------------------- /src/expressions.md: -------------------------------------------------------------------------------- 1 | # 表达式 2 | 3 | ## 块 4 | 5 | 块表达式必须在首行 `{` 后和末行 `}` 前加换行符,除非根据其他样式规则可以写成单行。 6 | 7 | 代码块前的关键字(如 `unsafe` 或 `async`)必须与开头的括号在同一行,关键字与开头的括号之间用一个空格隔开。缩进代码块的内容。 8 | 9 | ```rust,ignore 10 | fn block_as_stmt() { 11 | a_call(); 12 | 13 | { 14 | a_call_inside_a_block(); 15 | 16 | // a comment in a block 17 | the_value 18 | } 19 | } 20 | 21 | fn block_as_expr() { 22 | let foo = { 23 | a_call_inside_a_block(); 24 | 25 | // a comment in a block 26 | the_value 27 | }; 28 | } 29 | 30 | fn unsafe_block_as_stmt() { 31 | a_call(); 32 | 33 | unsafe { 34 | a_call_inside_a_block(); 35 | 36 | // a comment in a block 37 | the_value 38 | } 39 | } 40 | ``` 41 | 42 | If a block has an attribute, put it on its own line before the block: 43 | 44 | ```rust,ignore 45 | fn block_as_stmt() { 46 | #[an_attribute] 47 | { 48 | #![an_inner_attribute] 49 | 50 | // a comment in a block 51 | the_value 52 | } 53 | } 54 | ``` 55 | 56 | Avoid writing comments on the same lines as either of the braces. 57 | 58 | Write an empty block as `{}`. 59 | 60 | Write a block on a single line if: 61 | 62 | * it is either used in expression position (not statement position) or is an 63 | unsafe block in statement position, 64 | * it contains a single-line expression and no statements, and 65 | * it contains no comments 66 | 67 | For a single-line block, put spaces after the opening brace and before the 68 | closing brace. 69 | 70 | Examples: 71 | 72 | ```rust,ignore 73 | fn main() { 74 | // Single line 75 | let _ = { a_call() }; 76 | let _ = unsafe { a_call() }; 77 | 78 | // Not allowed on one line 79 | // Statement position. 80 | { 81 | a_call() 82 | } 83 | 84 | // Contains a statement 85 | let _ = { 86 | a_call(); 87 | }; 88 | unsafe { 89 | a_call(); 90 | } 91 | 92 | // Contains a comment 93 | let _ = { 94 | // A comment 95 | }; 96 | let _ = { 97 | // A comment 98 | a_call() 99 | }; 100 | 101 | // Multiple lines 102 | let _ = { 103 | a_call(); 104 | another_call() 105 | }; 106 | let _ = { 107 | a_call( 108 | an_argument, 109 | another_arg, 110 | ) 111 | }; 112 | } 113 | ``` 114 | 115 | 116 | ## Closures 117 | 118 | Don't put any extra spaces before the first `|` (unless the closure is prefixed 119 | by a keyword such as `move`); put a space between the second `|` and the 120 | expression of the closure. Between the `|`s, use function definition syntax, 121 | but elide types where possible. 122 | 123 | Use closures without the enclosing `{}`, if possible. Add the `{}` when you have 124 | a return type, when there are statements, when there are comments inside the 125 | closure, or when the body expression is a control-flow expression that spans 126 | multiple lines. If using braces, follow the rules above for blocks. Examples: 127 | 128 | ```rust,ignore 129 | |arg1, arg2| expr 130 | 131 | move |arg1: i32, arg2: i32| -> i32 { 132 | expr1; 133 | expr2 134 | } 135 | 136 | || Foo { 137 | field1, 138 | field2: 0, 139 | } 140 | 141 | || { 142 | if true { 143 | blah 144 | } else { 145 | boo 146 | } 147 | } 148 | 149 | |x| unsafe { 150 | expr 151 | } 152 | ``` 153 | 154 | 155 | ## Struct literals 156 | 157 | If a struct literal is *small*, format it on a single line, and do not use a 158 | trailing comma. If not, split it across multiple lines, with each field on its 159 | own block-indented line, and use a trailing comma. 160 | 161 | For each `field: value` entry, put a space after the colon only. 162 | 163 | Put a space before the opening brace. In the single-line form, put spaces after 164 | the opening brace and before the closing brace. 165 | 166 | ```rust,ignore 167 | Foo { field1, field2: 0 } 168 | let f = Foo { 169 | field1, 170 | field2: an_expr, 171 | }; 172 | ``` 173 | 174 | Functional record update syntax is treated like a field, but it must never have 175 | a trailing comma. Do not put a space after `..`. 176 | 177 | ```rust,ignore 178 | let f = Foo { 179 | field1, 180 | ..an_expr 181 | }; 182 | ``` 183 | 184 | 185 | ## Tuple literals 186 | 187 | Use a single-line form where possible. Do not put spaces between the opening 188 | parenthesis and the first element, or between the last element and the closing 189 | parenthesis. Separate elements with a comma followed by a space. 190 | 191 | Where a single-line form is not possible, write the tuple across 192 | multiple lines, with each element of the tuple on its own block-indented line, 193 | and use a trailing comma. 194 | 195 | ```rust,ignore 196 | (a, b, c) 197 | 198 | let x = ( 199 | a_long_expr, 200 | another_very_long_expr, 201 | ); 202 | ``` 203 | 204 | 205 | ## Tuple struct literals 206 | 207 | Do not put space between the identifier and the opening parenthesis. Otherwise, 208 | follow the rules for tuple literals: 209 | 210 | ```rust,ignore 211 | Foo(a, b, c) 212 | 213 | let x = Foo( 214 | a_long_expr, 215 | another_very_long_expr, 216 | ); 217 | ``` 218 | 219 | 220 | ## Enum literals 221 | 222 | Follow the formatting rules for the various struct literals. Prefer using the 223 | name of the enum as a qualifying name, unless the enum is in the prelude: 224 | 225 | ```rust,ignore 226 | Foo::Bar(a, b) 227 | Foo::Baz { 228 | field1, 229 | field2: 1001, 230 | } 231 | Ok(an_expr) 232 | ``` 233 | 234 | 235 | ## Array literals 236 | 237 | Write small array literals on a single line. Do not put spaces between the opening 238 | square bracket and the first element, or between the last element and the closing 239 | square bracket. Separate elements with a comma followed by a space. 240 | 241 | If using the repeating initializer, put a space after the semicolon 242 | only. 243 | 244 | Apply the same rules if using `vec!` or similar array-like macros; always use 245 | square brackets with such macros. Examples: 246 | 247 | ```rust,ignore 248 | fn main() { 249 | let x = [1, 2, 3]; 250 | let y = vec![a, b, c, d]; 251 | let a = [42; 10]; 252 | } 253 | ``` 254 | 255 | For arrays that have to be broken across lines, if using the repeating 256 | initializer, break after the `;`, not before. Otherwise, follow the rules below 257 | for function calls. In any case, block-indent the contents of the initializer, 258 | and put line breaks after the opening square bracket and before the closing 259 | square bracket: 260 | 261 | ```rust,ignore 262 | fn main() { 263 | [ 264 | a_long_expression(); 265 | 1234567890 266 | ] 267 | let x = [ 268 | an_expression, 269 | another_expression, 270 | a_third_expression, 271 | ]; 272 | } 273 | ``` 274 | 275 | 276 | ## Array accesses, indexing, and slicing. 277 | 278 | Don't put spaces around the square brackets. Avoid breaking lines if possible. 279 | Never break a line between the target expression and the opening square 280 | bracket. If the indexing expression must be broken onto a subsequent line, or 281 | spans multiple lines itself, then block-indent the indexing expression, and put 282 | newlines after the opening square bracket and before the closing square 283 | bracket: 284 | 285 | Examples: 286 | 287 | ```rust,ignore 288 | fn main() { 289 | foo[42]; 290 | &foo[..10]; 291 | bar[0..100]; 292 | foo[4 + 5 / bar]; 293 | a_long_target[ 294 | a_long_indexing_expression 295 | ]; 296 | } 297 | ``` 298 | 299 | ## Unary operations 300 | 301 | Do not include a space between a unary op and its operand (i.e., `!x`, not 302 | `! x`). However, there must be a space after `&mut`. Avoid line-breaking 303 | between a unary operator and its operand. 304 | 305 | ## Binary operations 306 | 307 | Do include spaces around binary ops (i.e., `x + 1`, not `x+1`) (including `=` 308 | and other assignment operators such as `+=` or `*=`). 309 | 310 | For comparison operators, because for `T op U`, `&T op &U` is also implemented: 311 | if you have `t: &T`, and `u: U`, prefer `*t op u` to `t op &u`. In general, 312 | within expressions, prefer dereferencing to taking references, unless necessary 313 | (e.g. to avoid an unnecessarily expensive operation). 314 | 315 | Use parentheses liberally; do not necessarily elide them due to precedence. 316 | Tools should not automatically insert or remove parentheses. Do not use spaces 317 | to indicate precedence. 318 | 319 | If line-breaking, block-indent each subsequent line. For assignment operators, 320 | break after the operator; for all other operators, put the operator on the 321 | subsequent line. Put each sub-expression on its own line: 322 | 323 | ```rust,ignore 324 | foo_bar 325 | + bar 326 | + baz 327 | + qux 328 | + whatever 329 | ``` 330 | 331 | Prefer line-breaking at an assignment operator (either `=` or `+=`, etc.) rather 332 | than at other binary operators. 333 | 334 | ## Control flow 335 | 336 | Do not include extraneous parentheses for `if` and `while` expressions. 337 | 338 | ```rust,ignore 339 | if true { 340 | } 341 | ``` 342 | 343 | is better than 344 | 345 | ```rust,ignore 346 | if (true) { 347 | } 348 | ``` 349 | 350 | Do include extraneous parentheses if it makes an arithmetic or logic expression 351 | easier to understand (`(x * 15) + (y * 20)` is fine) 352 | 353 | ## Function calls 354 | 355 | Do not put a space between the function name, and the opening parenthesis. 356 | 357 | Do not put a space between an argument, and the comma which follows. 358 | 359 | Do put a space between an argument, and the comma which precedes it. 360 | 361 | Prefer not to break a line in the callee expression. 362 | 363 | ### Single-line calls 364 | 365 | Do not put a space between the function name and open paren, between the open 366 | paren and the first argument, or between the last argument and the close paren. 367 | 368 | Do not put a comma after the last argument. 369 | 370 | ```rust,ignore 371 | foo(x, y, z) 372 | ``` 373 | 374 | ### Multi-line calls 375 | 376 | If the function call is not *small*, it would otherwise over-run the max width, 377 | or any argument or the callee is multi-line, then format the call across 378 | multiple lines. In this case, put each argument on its own block-indented line, 379 | break after the opening parenthesis and before the closing parenthesis, 380 | and use a trailing comma: 381 | 382 | ```rust,ignore 383 | a_function_call( 384 | arg1, 385 | a_nested_call(a, b), 386 | ) 387 | ``` 388 | 389 | 390 | ## Method calls 391 | 392 | Follow the function rules for calling. 393 | 394 | Do not put any spaces around the `.`. 395 | 396 | ```rust,ignore 397 | x.foo().bar().baz(x, y, z); 398 | ``` 399 | 400 | 401 | ## Macro uses 402 | 403 | If a macro can be parsed like other constructs, format it like those 404 | constructs. For example, a macro use `foo!(a, b, c)` can be parsed like a 405 | function call (ignoring the `!`), so format it using the rules for function 406 | calls. 407 | 408 | ### Special case macros 409 | 410 | For macros which take a format string, if all other arguments are *small*, 411 | format the arguments before the format string on a single line if they fit, and 412 | format the arguments after the format string on a single line if they fit, with 413 | the format string on its own line. If the arguments are not small or do not 414 | fit, put each on its own line as with a function. For example: 415 | 416 | ```rust,ignore 417 | println!( 418 | "Hello {} and {}", 419 | name1, name2, 420 | ); 421 | 422 | assert_eq!( 423 | x, y, 424 | "x and y were not equal, see {}", 425 | reason, 426 | ); 427 | ``` 428 | 429 | 430 | ## Casts (`as`) 431 | 432 | Put spaces before and after `as`: 433 | 434 | ```rust,ignore 435 | let cstr = "Hi\0" as *const str as *const [u8] as *const std::os::raw::c_char; 436 | ``` 437 | 438 | 439 | ## Chains of fields and method calls 440 | 441 | A chain is a sequence of field accesses, method calls, and/or uses of the try 442 | operator `?`. E.g., `a.b.c().d` or `foo?.bar().baz?`. 443 | 444 | Format the chain on one line if it is "small" and otherwise possible to do so. 445 | If formatting on multiple lines, put each field access or method call in the 446 | chain on its own line, with the line-break before the `.` and after any `?`. 447 | Block-indent each subsequent line: 448 | 449 | ```rust,ignore 450 | let foo = bar 451 | .baz? 452 | .qux(); 453 | ``` 454 | 455 | If the length of the last line of the first element plus its indentation is 456 | less than or equal to the indentation of the second line, then combine the 457 | first and second lines if they fit. Apply this rule recursively. 458 | 459 | ```rust,ignore 460 | x.baz? 461 | .qux() 462 | 463 | x.y.z 464 | .qux() 465 | 466 | let foo = x 467 | .baz? 468 | .qux(); 469 | 470 | foo( 471 | expr1, 472 | expr2, 473 | ).baz? 474 | .qux(); 475 | ``` 476 | 477 | ### Multi-line elements 478 | 479 | If any element in a chain is formatted across multiple lines, put that element 480 | and any later elements on their own lines. 481 | 482 | ```rust,ignore 483 | a.b.c()? 484 | .foo( 485 | an_expr, 486 | another_expr, 487 | ) 488 | .bar 489 | .baz 490 | ``` 491 | 492 | Note there is block indent due to the chain and the function call in the above 493 | example. 494 | 495 | Prefer formatting the whole chain in multi-line style and each element on one 496 | line, rather than putting some elements on multiple lines and some on a single 497 | line, e.g., 498 | 499 | ```rust,ignore 500 | // Better 501 | self.pre_comment 502 | .as_ref() 503 | .map_or(false, |comment| comment.starts_with("//")) 504 | 505 | // Worse 506 | self.pre_comment.as_ref().map_or( 507 | false, 508 | |comment| comment.starts_with("//"), 509 | ) 510 | ``` 511 | 512 | ## Control flow expressions 513 | 514 | This section covers `if`, `if let`, `loop`, `while`, `while let`, and `for` 515 | expressions. 516 | 517 | Put the keyword, any initial clauses, and the opening brace of the block all on 518 | a single line, if they fit. Apply the usual rules for [block 519 | formatting](#blocks) to the block. 520 | 521 | If there is an `else` component, then put the closing brace, `else`, any 522 | following clause, and the opening brace all on the same line, with a single 523 | space before and after the `else` keyword: 524 | 525 | ```rust,ignore 526 | if ... { 527 | ... 528 | } else { 529 | ... 530 | } 531 | 532 | if let ... { 533 | ... 534 | } else if ... { 535 | ... 536 | } else { 537 | ... 538 | } 539 | ``` 540 | 541 | If the control line needs to be broken, prefer to break before the `=` in `* 542 | let` expressions and before `in` in a `for` expression; block-indent the 543 | following line. If the control line is broken for any reason, put the opening 544 | brace on its own line, not indented. Examples: 545 | 546 | ```rust,ignore 547 | while let Some(foo) 548 | = a_long_expression 549 | { 550 | ... 551 | } 552 | 553 | for foo 554 | in a_long_expression 555 | { 556 | ... 557 | } 558 | 559 | if a_long_expression 560 | && another_long_expression 561 | || a_third_long_expression 562 | { 563 | ... 564 | } 565 | ``` 566 | 567 | Where the initial clause spans multiple lines and ends with one or more closing 568 | parentheses, square brackets, or braces, and there is nothing else on that 569 | line, and that line is not indented beyond the indent on the first line of the 570 | control flow expression, then put the opening brace of the block on the same 571 | line with a preceding space. For example: 572 | 573 | ```rust,ignore 574 | if !self.config.file_lines().intersects( 575 | &self.codemap.lookup_line_range( 576 | stmt.span, 577 | ), 578 | ) { // Opening brace on same line as initial clause. 579 | ... 580 | } 581 | ``` 582 | 583 | 584 | ### Single line `if else` 585 | 586 | Put an `if else` or `if let else` on a single line if it occurs in expression 587 | context (i.e., is not a standalone statement), it contains a single `else` 588 | clause, and is *small*: 589 | 590 | ```rust,ignore 591 | let y = if x { 0 } else { 1 }; 592 | 593 | // Examples that must be multi-line. 594 | let y = if something_very_long { 595 | not_small 596 | } else { 597 | also_not_small 598 | }; 599 | 600 | if x { 601 | 0 602 | } else { 603 | 1 604 | } 605 | ``` 606 | 607 | 608 | ## Match 609 | 610 | Prefer not to line-break inside the discriminant expression. Always break after 611 | the opening brace and before the closing brace. Block-indent the match arms 612 | once: 613 | 614 | ```rust,ignore 615 | match foo { 616 | // arms 617 | } 618 | 619 | let x = match foo.bar.baz() { 620 | // arms 621 | }; 622 | ``` 623 | 624 | Use a trailing comma for a match arm if and only if not using a block. 625 | 626 | Never start a match arm pattern with `|`: 627 | 628 | ```rust,ignore 629 | match foo { 630 | // Don't do this. 631 | | foo => bar, 632 | // Or this. 633 | | a_very_long_pattern 634 | | another_pattern 635 | | yet_another_pattern 636 | | a_fourth_pattern => { 637 | ... 638 | } 639 | } 640 | ``` 641 | 642 | Prefer: 643 | 644 | ```rust,ignore 645 | match foo { 646 | foo => bar, 647 | a_very_long_pattern 648 | | another_pattern 649 | | yet_another_pattern 650 | | a_fourth_pattern => { 651 | ... 652 | } 653 | } 654 | ``` 655 | 656 | Avoid splitting the left-hand side (before the `=>`) of a match arm where 657 | possible. If the right-hand side of the match arm is kept on the same line, 658 | never use a block (unless the block is empty). 659 | 660 | If the right-hand side consists of multiple statements, or has line comments, 661 | or the start of the line does not fit on the same line as the left-hand side, 662 | use a block. Do not flatten a right-hand side block containing a single macro call 663 | because its expanded form could contain a trailing semicolon. 664 | 665 | Block-indent the body of a block arm. 666 | 667 | Examples: 668 | 669 | ```rust,ignore 670 | match foo { 671 | foo => bar, 672 | a_very_long_pattern | another_pattern if an_expression() => { 673 | no_room_for_this_expression() 674 | } 675 | foo => { 676 | // A comment. 677 | an_expression() 678 | } 679 | foo => { 680 | let a = statement(); 681 | an_expression() 682 | } 683 | bar => {} 684 | // Trailing comma on last item. 685 | foo => bar, 686 | baz => qux!(), 687 | lorem => { 688 | ipsum!() 689 | } 690 | } 691 | ``` 692 | 693 | If the body is a single expression with no line comments and not a control flow 694 | expression, start it on the same line as the left-hand side. If not, then it 695 | must be in a block. Example: 696 | 697 | ```rust,ignore 698 | match foo { 699 | // A combinable expression. 700 | foo => a_function_call(another_call( 701 | argument1, 702 | argument2, 703 | )), 704 | // A non-combinable expression 705 | bar => { 706 | a_function_call( 707 | another_call( 708 | argument1, 709 | argument2, 710 | ), 711 | another_argument, 712 | ) 713 | } 714 | } 715 | ``` 716 | 717 | ### Line-breaking 718 | 719 | If using a block form on the right-hand side of a match arm makes it possible 720 | to avoid breaking on the left-hand side, do that: 721 | 722 | ```rust,ignore 723 | // Assuming the following line does not fit in the max width 724 | a_very_long_pattern | another_pattern => ALongStructName { 725 | ... 726 | }, 727 | // Prefer this 728 | a_very_long_pattern | another_pattern => { 729 | ALongStructName { 730 | ... 731 | } 732 | } 733 | // To splitting the pattern. 734 | ``` 735 | 736 | Never break after `=>` without using the block form of the body. 737 | 738 | If the left-hand side must be split and there is an `if` clause, break before 739 | the `if` and block indent. In this case, always use a block body and start the 740 | body on a new line: 741 | 742 | ```rust,ignore 743 | a_very_long_pattern | another_pattern 744 | if expr => 745 | { 746 | ... 747 | } 748 | ``` 749 | 750 | If required to break the pattern, put each clause of the pattern on its own 751 | line with no additional indent, breaking before the `|`. If there is an `if` 752 | clause, use the above form: 753 | 754 | ```rust,ignore 755 | a_very_long_pattern 756 | | another_pattern 757 | | yet_another_pattern 758 | | a_forth_pattern => { 759 | ... 760 | } 761 | a_very_long_pattern 762 | | another_pattern 763 | | yet_another_pattern 764 | | a_forth_pattern 765 | if expr => 766 | { 767 | ... 768 | } 769 | ``` 770 | 771 | If the pattern is multi-line, and the last line is less wide than the indent, do 772 | not put the `if` clause on a new line. E.g., 773 | 774 | ```rust,ignore 775 | Token::Dimension { 776 | value, 777 | ref unit, 778 | .. 779 | } if num_context.is_ok(context.parsing_mode, value) => { 780 | ... 781 | } 782 | ``` 783 | 784 | If every clause in a pattern is *small*, but the whole pattern does not fit on 785 | one line, then format the pattern across multiple lines with as many clauses 786 | per line as possible. Again, break before a `|`: 787 | 788 | ```rust,ignore 789 | foo | bar | baz 790 | | qux => { 791 | ... 792 | } 793 | ``` 794 | 795 | We define a pattern clause to be *small* if it fits on a single line and 796 | matches "small" in the following grammar: 797 | 798 | ```text 799 | small: 800 | - small_no_tuple 801 | - unary tuple constructor: `(` small_no_tuple `,` `)` 802 | - `&` small 803 | 804 | small_no_tuple: 805 | - single token 806 | - `&` small_no_tuple 807 | ``` 808 | 809 | E.g., `&&Some(foo)` matches, `Foo(4, Bar)` does not. 810 | 811 | 812 | ## Combinable expressions 813 | 814 | Where a function call has a single argument, and that argument is formatted 815 | across multiple-lines, format the outer call as if it were a single-line call, 816 | if the result fits. Apply the same combining behaviour to any similar 817 | expressions which have multi-line, block-indented lists of sub-expressions 818 | delimited by parentheses (e.g., macros or tuple struct literals). E.g., 819 | 820 | ```rust,ignore 821 | foo(bar( 822 | an_expr, 823 | another_expr, 824 | )) 825 | 826 | let x = foo(Bar { 827 | field: whatever, 828 | }); 829 | 830 | foo(|param| { 831 | action(); 832 | foo(param) 833 | }) 834 | 835 | let x = combinable([ 836 | an_expr, 837 | another_expr, 838 | ]); 839 | 840 | let arr = [combinable( 841 | an_expr, 842 | another_expr, 843 | )]; 844 | ``` 845 | 846 | Apply this behavior recursively. 847 | 848 | For a function with multiple arguments, if the last argument is a multi-line 849 | closure with an explicit block, there are no other closure arguments, and all 850 | the arguments and the first line of the closure fit on the first line, use the 851 | same combining behavior: 852 | 853 | ```rust,ignore 854 | foo(first_arg, x, |param| { 855 | action(); 856 | foo(param) 857 | }) 858 | ``` 859 | 860 | 861 | ## Ranges 862 | 863 | Do not put spaces in ranges, e.g., `0..10`, `x..=y`, `..x.len()`, `foo..`. 864 | 865 | When writing a range with both upper and lower bounds, if the line must be 866 | broken within the range, break before the range operator and block indent the 867 | second line: 868 | 869 | ```rust,ignore 870 | a_long_expression 871 | ..another_long_expression 872 | ``` 873 | 874 | For the sake of indicating precedence, if either bound is a compound 875 | expression, use parentheses around it, e.g., `..(x + 1)`, `(x.f)..(x.f.len())`, 876 | or `0..(x - 10)`. 877 | 878 | 879 | ## Hexadecimal literals 880 | 881 | Hexadecimal literals may use upper- or lower-case letters, but they must not be 882 | mixed within the same literal. Projects should use the same case for all 883 | literals, but we do not make a recommendation for either lower- or upper-case. 884 | 885 | # Patterns 886 | 887 | Format patterns like their corresponding expressions. See the section on 888 | `match` for additional formatting for patterns in match arms. 889 | -------------------------------------------------------------------------------- /src/items.md: -------------------------------------------------------------------------------- 1 | # 程序项 2 | 3 | 程序项(item,简称项)包括模块顶层允许使用的一系列内容。不过,Rust 也允许某些程序项出现在其他类型的程序项中,如函数中。无论程序项是出现在模块层还是出现在其他程序项中,都适用相同的格式约定。 4 | 5 | `extern crate` 语句必须放在文件的首位。它们必须按字母顺序排列。 6 | 7 | `use` 语句和模块声明(`mod foo;`,而不是 `mod { ... }`)必须放在其他程序项之前。将导入放在模块声明之前。按字母顺序排序,但 `self` 和 `super` 必须排在其他名称之前。 8 | 9 | 不要自动移动注有 `#[macro_use]` 的模块声明,因为这可能会改变语义。 10 | 11 | ## 函数定义 12 | 13 | 在 Rust 中,人们经常通过搜索 `fn [function-name]` 来查找函数,因此函数定义的格式必须能够满足这一点。 14 | 15 | 正确的排序和空格位置是: 16 | 17 | ```rust,ignore 18 | [pub] [unsafe] [extern ["ABI"]] fn foo(arg1: i32, arg2: i32) -> i32 { 19 | ... 20 | } 21 | ``` 22 | 23 | 避免在签名本身中添加注释。 24 | 25 | 如果函数签名不能放在一行内,则在开头括号后和结尾括号前分隔,并将每个参数放在自己的缩进行内。例如: 26 | 27 | ```rust,ignore 28 | fn foo( 29 | arg1: i32, 30 | arg2: i32, 31 | ) -> i32 { 32 | ... 33 | } 34 | ``` 35 | 36 | 注意最后一个参数后面的逗号。 37 | 38 | ## 元组和元组结构 39 | 40 | 像编写函数的参数列表一样编写类型列表。 41 | 42 | 像调用函数一样构建元组或元组结构体。 43 | 44 | ### 单行 45 | 46 | ```rust,ignore 47 | struct Bar(Type1, Type2); 48 | 49 | let x = Bar(11, 22); 50 | let y = (11, 22, 33); 51 | ``` 52 | 53 | ## Enums 54 | 55 | In the declaration, put each variant on its own line, block indented. 56 | 57 | Format each variant accordingly as either a struct (but without the `struct` 58 | keyword), a tuple struct, or an identifier (which doesn't require special 59 | formatting): 60 | 61 | ```rust,ignore 62 | enum FooBar { 63 | First(u32), 64 | Second, 65 | Error { 66 | err: Box, 67 | line: u32, 68 | }, 69 | } 70 | ``` 71 | 72 | If a struct variant is [*small*](index.html#small-items), format it on one 73 | line. In this case, do not use a trailing comma for the field list, but do put 74 | spaces around each brace: 75 | 76 | ```rust,ignore 77 | enum FooBar { 78 | Error { err: Box, line: u32 }, 79 | } 80 | ``` 81 | 82 | In an enum with multiple struct variants, if any struct variant is written on 83 | multiple lines, use the multi-line formatting for all struct variants. However, 84 | such a situation might be an indication that you should factor out the fields 85 | of the variant into their own struct. 86 | 87 | 88 | ## Structs and Unions 89 | 90 | Struct names follow on the same line as the `struct` keyword, with the opening 91 | brace on the same line when it fits within the right margin. All struct fields 92 | are indented once and end with a trailing comma. The closing brace is not 93 | indented and appears on its own line. 94 | 95 | ```rust,ignore 96 | struct Foo { 97 | a: A, 98 | b: B, 99 | } 100 | ``` 101 | 102 | If and only if the type of a field does not fit within the right margin, it is 103 | pulled down to its own line and indented again. 104 | 105 | ```rust,ignore 106 | struct Foo { 107 | a: A, 108 | long_name: 109 | LongType, 110 | } 111 | ``` 112 | 113 | Prefer using a unit struct (e.g., `struct Foo;`) to an empty struct (e.g., 114 | `struct Foo();` or `struct Foo {}`, these only exist to simplify code 115 | generation), but if you must use an empty struct, keep it on one line with no 116 | space between the braces: `struct Foo;` or `struct Foo {}`. 117 | 118 | The same guidelines are used for untagged union declarations. 119 | 120 | ```rust,ignore 121 | union Foo { 122 | a: A, 123 | b: B, 124 | long_name: 125 | LongType, 126 | } 127 | ``` 128 | 129 | 130 | ## Tuple structs 131 | 132 | Put the whole struct on one line if possible. Separate types within the 133 | parentheses using a comma and space. Don't use a trailing comma for a 134 | single-line tuple struct. Don't put spaces around the parentheses or semicolon: 135 | 136 | ```rust,ignore 137 | pub struct Foo(String, u8); 138 | ``` 139 | 140 | Prefer unit structs to empty tuple structs (these only exist to simplify code 141 | generation), e.g., `struct Foo;` rather than `struct Foo();`. 142 | 143 | For more than a few fields (in particular if the tuple struct does not fit on 144 | one line), prefer a proper struct with named fields. 145 | 146 | For a multi-line tuple struct, block-format the fields with a field on each 147 | line and a trailing comma: 148 | 149 | ```rust,ignore 150 | pub struct Foo( 151 | String, 152 | u8, 153 | ); 154 | ``` 155 | 156 | 157 | ## Traits 158 | 159 | Use block-indent for trait items. If there are no items, format the trait (including its `{}`) 160 | on a single line. Otherwise, break after the opening brace and before 161 | the closing brace: 162 | 163 | ```rust,ignore 164 | trait Foo {} 165 | 166 | pub trait Bar { 167 | ... 168 | } 169 | ``` 170 | 171 | If the trait has bounds, put a space after the colon but not before, 172 | and put spaces around each `+`, e.g., 173 | 174 | ```rust,ignore 175 | trait Foo: Debug + Bar {} 176 | ``` 177 | 178 | Prefer not to line-break in the bounds if possible (consider using a `where` 179 | clause). Prefer to break between bounds than to break any individual bound. If 180 | you must break the bounds, put each bound (including the first) on its own 181 | block-indented line, break before the `+` and put the opening brace on its own 182 | line: 183 | 184 | ```rust,ignore 185 | pub trait IndexRanges: 186 | Index, Output=Self> 187 | + Index, Output=Self> 188 | + Index, Output=Self> 189 | + Index 190 | { 191 | ... 192 | } 193 | ``` 194 | 195 | 196 | ## Impls 197 | 198 | Use block-indent for impl items. If there are no items, format the impl 199 | (including its `{}`) on a single line. Otherwise, break after the opening brace 200 | and before the closing brace: 201 | 202 | ```rust,ignore 203 | impl Foo {} 204 | 205 | impl Bar for Foo { 206 | ... 207 | } 208 | ``` 209 | 210 | Avoid line-breaking in the signature if possible. If a line break is required in 211 | a non-inherent impl, break immediately before `for`, block indent the concrete type 212 | and put the opening brace on its own line: 213 | 214 | ```rust,ignore 215 | impl Bar 216 | for Foo 217 | { 218 | ... 219 | } 220 | ``` 221 | 222 | 223 | ## Extern crate 224 | 225 | `extern crate foo;` 226 | 227 | Use spaces around keywords, no spaces around the semicolon. 228 | 229 | 230 | ### Modules 231 | 232 | ```rust,ignore 233 | mod foo { 234 | } 235 | ``` 236 | 237 | ```rust,ignore 238 | mod foo; 239 | ``` 240 | 241 | Use spaces around keywords and before the opening brace, no spaces around the 242 | semicolon. 243 | 244 | ### macro\_rules! 245 | 246 | Use `{}` for the full definition of the macro. 247 | 248 | ```rust,ignore 249 | macro_rules! foo { 250 | } 251 | ``` 252 | 253 | 254 | ## Generics 255 | 256 | Prefer to put a generics clause on one line. Break other parts of an item 257 | declaration rather than line-breaking a generics clause. If a generics clause is 258 | large enough to require line-breaking, prefer a `where` clause instead. 259 | 260 | Do not put spaces before or after `<` nor before `>`. Only put a space after 261 | `>` if it is followed by a word or opening brace, not an opening parenthesis. 262 | Put a space after each comma. Do not use a trailing comma for a single-line 263 | generics clause. 264 | 265 | ```rust,ignore 266 | fn foo(x: Vec, y: Vec) ... 267 | 268 | impl SomeType { ... 269 | ``` 270 | 271 | If the generics clause must be formatted across multiple lines, put each 272 | parameter on its own block-indented line, break after the opening `<` and 273 | before the closing `>`, and use a trailing comma. 274 | 275 | ```rust,ignore 276 | fn foo< 277 | T: Display, 278 | U: Debug, 279 | >(x: Vec, y: Vec) ... 280 | ``` 281 | 282 | If an associated type is bound in a generic type, put spaces around the `=`: 283 | 284 | ```rust,ignore 285 | > 286 | ``` 287 | 288 | Prefer to use single-letter names for generic parameters. 289 | 290 | 291 | ## `where` clauses 292 | 293 | These rules apply for `where` clauses on any item. 294 | 295 | If immediately following a closing bracket of any kind, write the keyword 296 | `where` on the same line, with a space before it. 297 | 298 | Otherwise, put `where` on a new line at the same indentation level. Put each 299 | component of a `where` clause on its own line, block-indented. Use a trailing 300 | comma, unless the clause is terminated with a semicolon. If the `where` clause 301 | is followed by a block (or assignment), start that block on a new line. 302 | Examples: 303 | 304 | ```rust,ignore 305 | fn function(args) 306 | where 307 | T: Bound, 308 | U: AnotherBound, 309 | { 310 | body 311 | } 312 | 313 | fn foo( 314 | args 315 | ) -> ReturnType 316 | where 317 | T: Bound, 318 | { 319 | body 320 | } 321 | 322 | fn foo( 323 | args, 324 | ) where 325 | T: Bound, 326 | U: AnotherBound, 327 | { 328 | body 329 | } 330 | 331 | fn foo( 332 | args 333 | ) -> ReturnType 334 | where 335 | T: Bound, 336 | U: AnotherBound; // Note, no trailing comma. 337 | 338 | // Note that where clauses on `type` aliases are not enforced and should not 339 | // be used. 340 | type Foo 341 | where 342 | T: Bound 343 | = Bar; 344 | ``` 345 | 346 | If a `where` clause is very short, prefer using an inline bound on the type 347 | parameter. 348 | 349 | If a component of a `where` clause does not fit and contains `+`, break it 350 | before each `+` and block-indent the continuation lines. Put each bound on its 351 | own line. E.g., 352 | 353 | ```rust,ignore 354 | impl IndexRanges for T 355 | where 356 | T: Index, Output = Self::Output> 357 | + Index, Output = Self::Output> 358 | + Index, Output = Self::Output> 359 | + Index, Output = Self::Output> 360 | + Index, Output = Self::Output> 361 | + Index, 362 | ``` 363 | 364 | ## Type aliases 365 | 366 | Keep type aliases on one line when they fit. If necessary to break the line, do 367 | so after the `=`, and block-indent the right-hand side: 368 | 369 | ```rust,ignore 370 | pub type Foo = Bar; 371 | 372 | // If multi-line is required 373 | type VeryLongType = 374 | AnEvenLongerType>; 375 | ``` 376 | 377 | Where possible avoid `where` clauses and keep type constraints inline. Where 378 | that is not possible split the line before and after the `where` clause (and 379 | split the `where` clause as normal), e.g., 380 | 381 | ```rust,ignore 382 | type VeryLongType 383 | where 384 | T: U::AnAssociatedType, 385 | U: SomeBound, 386 | = AnEvenLongerType>; 387 | ``` 388 | 389 | 390 | ## Associated types 391 | 392 | Format associated types like type aliases. Where an associated type has a 393 | bound, put a space after the colon but not before: 394 | 395 | ```rust,ignore 396 | pub type Foo: Bar; 397 | ``` 398 | 399 | ## extern items 400 | 401 | When writing extern items (such as `extern "C" fn`), always specify the ABI. 402 | For example, write `extern "C" fn foo ...`, not `extern fn foo ...`, or 403 | `extern "C" { ... }`. 404 | 405 | ## Imports (`use` statements) 406 | 407 | Format imports on one line where possible. Don't put spaces around braces. 408 | 409 | ```rust,ignore 410 | use a::b::c; 411 | use a::b::d::*; 412 | use a::b::{foo, bar, baz}; 413 | ``` 414 | 415 | ### Large list imports 416 | 417 | Prefer to use multiple imports rather than a multi-line import. However, tools 418 | should not split imports by default. 419 | 420 | If an import does require multiple lines (either because a list of single names 421 | does not fit within the max width, or because of the rules for nested imports 422 | below), then break after the opening brace and before the closing brace, use a 423 | trailing comma, and block indent the names. 424 | 425 | ```rust,ignore 426 | // Prefer 427 | foo::{long, list, of, imports}; 428 | foo::{more, imports}; 429 | 430 | // If necessary 431 | foo::{ 432 | long, list, of, imports, more, 433 | imports, // Note trailing comma 434 | }; 435 | ``` 436 | 437 | ### Ordering of imports 438 | 439 | A *group* of imports is a set of imports on the same or sequential lines. One or 440 | more blank lines or other items (e.g., a function) separate groups of imports. 441 | 442 | Within a group of imports, imports must be sorted ASCIIbetically (uppercase 443 | before lowercase). Groups of imports must not be merged or re-ordered. 444 | 445 | E.g., input: 446 | 447 | ```rust,ignore 448 | use d; 449 | use c; 450 | 451 | use b; 452 | use a; 453 | ``` 454 | 455 | output: 456 | 457 | ```rust,ignore 458 | use c; 459 | use d; 460 | 461 | use a; 462 | use b; 463 | ``` 464 | 465 | Because of `macro_use`, attributes must also start a new group and prevent 466 | re-ordering. 467 | 468 | ### Ordering list import 469 | 470 | Names in a list import must be sorted ASCIIbetically, but with `self` and 471 | `super` first, and groups and glob imports last. This applies recursively. For 472 | example, `a::*` comes before `b::a` but `a::b` comes before `a::*`. E.g., 473 | `use foo::bar::{a, b::c, b::d, b::d::{x, y, z}, b::{self, r, s}};`. 474 | 475 | ### Normalisation 476 | 477 | Tools must make the following normalisations, recursively: 478 | 479 | * `use a::self;` -> `use a;` 480 | * `use a::{};` -> (nothing) 481 | * `use a::{b};` -> `use a::b;` 482 | 483 | Tools must not otherwise merge or un-merge import lists or adjust glob imports 484 | (without an explicit option). 485 | 486 | ### Nested imports 487 | 488 | If there are any nested imports in a list import, then use the multi-line form, 489 | even if the import fits on one line. Each nested import must be on its own line, 490 | but non-nested imports must be grouped on as few lines as possible. 491 | 492 | For example, 493 | 494 | ```rust,ignore 495 | use a::b::{ 496 | x, y, z, 497 | u::{...}, 498 | w::{...}, 499 | }; 500 | ``` 501 | 502 | 503 | ### Merging/un-merging imports 504 | 505 | An example: 506 | 507 | ```rust,ignore 508 | // Un-merged 509 | use a::b; 510 | use a::c::d; 511 | 512 | // Merged 513 | use a::{b, c::d}; 514 | ``` 515 | 516 | Tools must not merge or un-merge imports by default. They may offer merging or 517 | un-merging as an option. 518 | -------------------------------------------------------------------------------- /src/nightly.md: -------------------------------------------------------------------------------- 1 | 本章记录了开发版特定(nightly-only,直译为:夜间特定)语法的样式和格式。风格指南的其余部分记录了 Rust 稳定语法的风格;开发版特定语法仅出现在本章。这里的每一节都包含了特性门类的名称,因此在 Rust 代码库中搜索(例如 `git grep`)开发版特性时,也会出现样式指南部分。 2 | 3 | 开发版特定语法的样式和格式应从本章移除,并在稳定化时整合到样式指南的相应章节中。 4 | 5 | 与样式指南的其他部分相比,本章的稳定性无法保证。有关对本章进行中断更改的夜间格式化程序,请参阅样式团队政策。 6 | -------------------------------------------------------------------------------- /src/principles.md: -------------------------------------------------------------------------------- 1 | # 指导原则和基本原理 2 | 3 | 在确定风格指南时,风格团队遵循以下指导原则(按大致优先顺序排列): 4 | 5 | - 可读性 6 | - 可扫描性 7 | - 避免格式误导 8 | - 可访问性——使用各种硬件(包括非视觉可访问界面)的用户均可阅读辑 9 | - 代码在没有语法高亮或集成开发环境辅助的情况下的可读性,如 rustc 错误信息、差异内容、grep 和其他纯文本情况下的可读性 10 | - 美感 11 | - 美感 12 | - 与其他语言/工具保持一 13 | - 特殊性 14 | - 与版本控制实践兼容——保留差异、便于合并等 15 | - 防止向右偏移(preventing rightward drift) 16 | - 尽量减少垂直空 17 | - 应用 18 | - 易于手动应用 19 | - 易于实施(在 `rustfmt`` 和其他工具/编辑器/代码生成器中) 20 | - 内部一致性 21 | - 格式规则简单 22 | -------------------------------------------------------------------------------- /src/statements.md: -------------------------------------------------------------------------------- 1 | # 语句 2 | 3 | ## `let` 语句 4 | 5 | 在 `:` 后面和 `=` 的两边(若它们存在的话)空一格。分号前不要空格。 6 | 7 | ```rust,ignore 8 | // 一条注释。 9 | let pattern: Type = expr; 10 | 11 | let pattern; 12 | let pattern: Type; 13 | let pattern = expr; 14 | ``` 15 | 16 | 如果可能,将声明格式化成一行。如果不可能,则在 `=` 之后尝试分割,如果声明适合在两行中进行。将表达式块缩进。 17 | 18 | ```rust,ignore 19 | let pattern: Type = 20 | expr; 21 | ``` 22 | 23 | 如果第一行仍不能排在一行上,则在 `:` 之后分行,并使用块缩进。即使在 `:` 后分行后类型还需要多行,也应将第一行放在与 `:` 相同的行上,并遵守[合并规则](expressions.html#combinable-expressions)。 24 | 25 | ```rust,ignore 26 | let pattern: 27 | Type = 28 | expr; 29 | ``` 30 | 31 | 例如: 32 | 33 | ```rust,ignore 34 | let Foo { 35 | f: abcd, 36 | g: qwer, 37 | }: Foo = 38 | Foo { f, g }; 39 | 40 | let (abcd, 41 | defg): 42 | Baz = 43 | { ... } 44 | ``` 45 | 46 | 如果表达式包含多行,若表达式的第一行适合在余下空位上,则表达式与 `=` 保留在同一行,表达式的其余部分不再缩进。如果第一行不合适,则将表达式放在后面的行中,分块缩进。如果表达式是一个代码块,且类型或模式覆盖多行,则将开头括号放在新的一行,且不缩进(这样可以将代码块内部与类型分开);否则,开头括号放在 `=` 之后。 47 | 48 | 示例: 49 | 50 | ```rust,ignore 51 | let foo = Foo { 52 | f: abcd, 53 | g: qwer, 54 | }; 55 | 56 | let foo = 57 | ALongName { 58 | f: abcd, 59 | g: qwer, 60 | }; 61 | 62 | let foo: Type = { 63 | an_expression(); 64 | ... 65 | }; 66 | 67 | let foo: 68 | ALongType = 69 | { 70 | an_expression(); 71 | ... 72 | }; 73 | 74 | let Foo { 75 | f: abcd, 76 | g: qwer, 77 | }: Foo = Foo { 78 | f: blimblimblim, 79 | g: blamblamblam, 80 | }; 81 | 82 | let Foo { 83 | f: abcd, 84 | g: qwer, 85 | }: Foo = foo( 86 | blimblimblim, 87 | blamblamblam, 88 | ); 89 | ``` 90 | 91 | ### else 块(let-else 语句) 92 | 93 | 一个 let 语句可以包含一个 `else` 组件,使其成为一个 let-else 语句。在这种情况下,应始终对 else 块前面的组件(即 `let pattern: Type = initializer_expr` 部分)采用与[其他 let 语句](#let-语句)相同的格式化规则。 94 | 95 | 如果以下条件都符合,则将整个 let-else 语句格式化为一行: 96 | 97 | - 整个语句很**短** 98 | - `else` 块只包含一个单行表达式,不包含任何语句 99 | - `else` 块不包含注释 100 | - `else` 块前面的 let 语句组件可以格式化为单行 101 | 102 | ```rust,ignore 103 | let Some(1) = opt else { return }; 104 | ``` 105 | 106 | 否则,let-else 语句需要换行。 107 | 108 | 如果将 let-else 语句换成多行,切勿在`else` 和 `{` 之间换行,一定要在 `}` 之前换行。 109 | 110 | 如果 `else` 前面的 let 语句组件可以格式化为一行,但 let-else 不符合完全放在一行的条件,则应将 `else {` 放在初始化表达式的同一行,并在两者之间留一个空格,然后在 `{` 之后换行。缩进结尾的 `}` 以匹配 `let`,并将包含的代码块再缩进一步。 111 | 112 | ```rust,ignore 113 | let Some(1) = opt else { 114 | return; 115 | }; 116 | 117 | let Some(1) = opt else { 118 | // nope 119 | return 120 | }; 121 | ``` 122 | 123 | 如果 `else` 前面的 let 语句组件可以在一行中格式化,但 `else {` 不能在同一行中格式化时,则在 `else` 之前换行。 124 | 125 | ```rust,ignore 126 | let Some(x) = some_really_really_really_really_really_really_really_really_really_long_name 127 | else { 128 | return; 129 | }; 130 | ``` 131 | 132 | 如果初始化表达式为多行,则在且仅在以下所有条件都符合的情况下,将 `else` 关键字和代码块的开头括号(即 `else {`)放在与初始化表达式结尾相同的行上,并在它们之间留一个空格: 133 | 134 | - 初始化表达式以一个或多个结束括号、方括号和/或大括号结束 135 | - 该行没有其他内容 136 | - 该行的缩进级别与初始 `let` 关键字的缩进级别相同 137 | 138 | 例如: 139 | 140 | ```rust,ignore 141 | let Some(x) = y.foo( 142 | "abc", 143 | fairly_long_identifier, 144 | "def", 145 | "123456", 146 | "string", 147 | "cheese", 148 | ) else { 149 | bar() 150 | } 151 | ``` 152 | 153 | 否则,将 `else` 关键字和开头括号放在初始化表达式结束后的下一行,`else` 关键字的缩进级别与 `let` 关键字的缩进级别相同。 154 | 155 | 例如: 156 | 157 | ```rust,ignore 158 | fn main() { 159 | let Some(x) = abcdef() 160 | .foo( 161 | "abc", 162 | some_really_really_really_long_ident, 163 | "ident", 164 | "123456", 165 | ) 166 | .bar() 167 | .baz() 168 | .qux("fffffffffffffffff") 169 | else { 170 | return 171 | }; 172 | 173 | let Some(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) = 174 | bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 175 | else { 176 | return; 177 | }; 178 | 179 | let LongStructName(AnotherStruct { 180 | multi, 181 | line, 182 | pattern, 183 | }) = slice.as_ref() 184 | else { 185 | return; 186 | }; 187 | 188 | let LongStructName(AnotherStruct { 189 | multi, 190 | line, 191 | pattern, 192 | }) = multi_line_function_call( 193 | arg1, 194 | arg2, 195 | arg3, 196 | arg4, 197 | ) else { 198 | return; 199 | }; 200 | } 201 | ``` 202 | 203 | ## 在语句位置使用宏 204 | 205 | 在语句位置使用宏时,使用圆括号或方括号作为分隔符,并以分号结束。请勿在名称、`!`、分隔符或 `;` 前后使用空格。 206 | 207 | ```rust,ignore 208 | // 注释 209 | a_macro!(...); 210 | ``` 211 | 212 | ## 语句位置中的表达式 213 | 214 | 表达式和分号之间不要加空格。 215 | 216 | ```rust,ignore 217 | ; 218 | ``` 219 | 220 | 用分号结束语句位置上的所有表达式,除非这些表达式以块结束或用作块的值。 221 | 222 | 例如: 223 | 224 | ```rust,ignore 225 | { 226 | an_expression(); 227 | expr_as_value() 228 | } 229 | 230 | return foo(); 231 | 232 | loop { 233 | break; 234 | } 235 | ``` 236 | 237 | 表达式为空类型时,即使可以传递,也要使用分号。例如: 238 | 239 | ```rust,ignore 240 | fn foo() { ... } 241 | 242 | fn bar() { 243 | foo(); 244 | } 245 | ``` 246 | -------------------------------------------------------------------------------- /src/types.md: -------------------------------------------------------------------------------- 1 | # 类型和约束 2 | 3 | ## 单行格式 4 | 5 | - `[T]` 不带空格 6 | - `[T; expr]`,例如:`[u32; 42]`、`[Vec; 10 * 2 + foo()]`(冒号后空格,方括号无空格) 7 | - `*const T`、`*mut T`(`*`后无空格,类型前有空格) 8 | - `&'a T`、`&T`、`&'a mut T`、`&mut T`(`&` 后无空格,其他单词用单个空格隔开) 9 | - `unsafe extern "C" fn<'a, 'b, 'c>(T, U, V) -> W` 或 `fn()`(关键字和符号后有空格,逗号后有空格,逗号后无空格,括号后无空格)。 10 | - `!` 与其他类型名称一样,`Name` 11 | - `(A, B, C, D)`(逗号后有空格,双引号无空格,除非是单元组,否则逗号后无空格) 12 | - ` as SomeTrait>::Foo::Bar` 或 F`oo::Bar` 或 `::Foo::Bar` (`::` 或尖括号后无空格,`as` 前后各有一个空格) 13 | - `Foo::Bar`(逗号后有空格,逗号前无空格,尖括号前后无空格) 14 | - `T + T + T`(类型和 `+` 之间用一个空格)。 15 | - `impl T + T + T`(关键字、类型和 `+`` 之间用空格隔开)。 16 | 17 | 类型中使用的括号不要空格,例如 `(Foo)`。 18 | 19 | ## 换行 20 | 21 | 尽可能避免在类型中换行。最好在最外层的范围内换行,例如,最好使用以下形式: 22 | 23 | ```rust,ignore 24 | Foo< 25 | Bar, 26 | Baz, 27 | > 28 | ``` 29 | 30 | 而不采用: 31 | 32 | ```rust,ignore 33 | Foo> 37 | ``` 38 | 39 | 如果一个类型需要换行才能适应,本节概括了在必要时应在何处换行。 40 | 41 | 必要时,在 `;` 后分隔 `[T; expr]`。 42 | 43 | 按照函数声明的规则断开函数类型。 44 | 45 | 按照泛型的规则断开泛型类型。 46 | 47 | 断开带 `+` 的类型,方法是在 `+` 之前断开,并在随后的行中用块缩进。断开此类类型时,应在**每个** `+` 之前断开: 48 | 49 | ```rust,ignore 50 | impl Clone 51 | + Copy 52 | + Debug 53 | 54 | Box< 55 | Clone 56 | + Copy 57 | + Debug 58 | > 59 | ``` 60 | --------------------------------------------------------------------------------