RustPrimer
  • Introduction
  • 初识Rust
  • 安装Rust
    • Linux
    • Mac
    • Windows
    • 版本管理工具: rustup
  • 编辑器
    • 前期准备
    • vim
    • emacs
    • vscode
    • atom
    • sublime
    • visual studio
    • spacemacs
  • Rust快速入门
    • Rust旅程
    • 变量绑定与原生类型
    • 数组、动态数组和字符串
    • 结构体与枚举
    • 控制流
    • 函数与方法
    • 特性
    • 注释与文档
    • 输入输出流
  • Cargo项目管理器
  • 基本程序结构
    • 注释
    • 条件
    • 循环
  • 类型、运算符和字符串
    • 基础类型
    • 复合类型
    • 字符串类
    • 基础运算符和字符串格式化
  • 函数
    • 函数参数
    • 函数返回值
    • 语句和表达式
    • 高阶函数
  • 模式匹配
    • match关键字
    • 模式 pattern
  • 特征 Trait
    • trait关键字
    • trait对象
  • 泛型
  • 可变性、所有权、租借和生命期
    • 所有权
    • 引用和借用
    • 生命周期
  • 闭包
    • 闭包的语法
    • 闭包的实现
    • 闭包作为参数和返回值
  • 集合类型 Collections
    • 动态数组 Vec
    • 哈希表 HashMap
  • 迭代器
    • 迭代器、适配器、消费者
  • 模块和包系统、Prelude
    • 模块 module 和包 crate
    • Prelude
  • Option、Result与错误处理
  • 输入与输出
  • 宏系统
  • 堆、栈与Box
  • 几种智能指针
    • Rc, Arc
    • Mutex, RwLock
    • Cell, RefCell
  • 类型系统中的几个常见 Trait
    • Into/From 及其在 String 和 &str 互转上的应用
    • AsRef, AsMut
    • Borrow, BorrowMut, ToOwned
    • Deref 与 Deref coercions
    • Cow 及其在 String 和 &str 上的应用
  • Send 和 Sync
  • 并发,并行,多线程编程
    • 线程
    • 消息传递
    • 共享内存
    • 同步
    • 并行
  • Unsafe、原始指针
    • Unsafe
    • 原始指针
  • FFI
    • rust调用ffi函数
    • 将rust编译成库
  • 运算符重载
  • 属性和编译器参数
    • 属性
    • 编译器参数
  • Cargo参数配置
  • 测试与评测
    • 测试 (testing)
    • 评测 (benchmark)
  • 代码风格
  • Any与反射
  • 安全(safe)
  • 常用数据结构实现
    • 栈结构
    • 队列
    • 二叉树
    • 优先队列
    • 链表
    • 图结构
  • 标准库介绍
    • 系统命令:调用grep
    • 目录操作:简单grep
    • 网络模块:W回音
  • 实战篇
    • 实战:Json处理
    • 实战:Web 应用开发入门
    • 实战:使用Postgresql数据库
  • 附录-术语表
Powered by GitBook
On this page
  • 空白
  • 空格
  • 折行
  • 对齐
  • 避免块注释
  • 文档注释
  • 总结行
  • 句子结构
  • 避免文档内注释
  • 解释上下文
  • 开始的大括号总是出现的同一行。
  • match 分支有大括号,除非是单行表达式。
  • return 语句有分号。
  • 行尾的逗号
  • 一般命名约定
  • 引用函数/方法名中的类型
  • 避免冗余的前缀
  • Getter/setter 方法
  • 断言
  • 导入
  • 避免 use *,除非在测试里
  • 当模块限定函数时,倾向于完全导入类型/traits。
  • 在 crate 级重新导出最重要的类型。
  • 类型和操作在一起定义。

Was this helpful?

代码风格

空白

  • 每行不能超出99个字符。

  • 缩进只用空格,不用TAB。

  • 行和文件末尾不要有空白。

空格

  • 二元运算符左右加空格,包括属性里的等号:

#[deprecated = "Use `bar` instead."]
fn foo(a: usize, b: usize) -> usize {
    a + b
}
  • 在分号和逗号后面加空格:

fn foo(a: Bar);

MyStruct { foo: 3, bar: 4 }

foo(bar, baz);
  • 在单行语句块或struct表达式的开始大括号之后和结束大括号之前加空格:

spawn(proc() { do_something(); })

Point { x: 0.1, y: 0.3 }

折行

  • 对于多行的函数签名,每个新行和第一个参数对齐。允许每行多个参数:

fn frobnicate(a: Bar, b: Bar,
              c: Bar, d: Bar)
              -> Bar {
    ...
}

fn foo<T: This,
       U: That>(
       a: Bar,
       b: Bar)
       -> Baz {
    ...
}
  • 多行函数调用一般遵循和签名统一的规则。然而,如果最后的参数开始了一个语句块,块的内容可以开始一个新行,缩进一层:

fn foo_bar(a: Bar, b: Bar,
           c: |Bar|) -> Bar {
    ...
}

// 可以在同一行:
foo_bar(x, y, |z| { z.transpose(y) });

// 也可以在新一行缩进函数体:
foo_bar(x, y, |z| {
    z.quux();
    z.rotate(x)
})

对齐

常见代码不必在行中用多余的空格来对齐。

// 好
struct Foo {
    short: f64,
    really_long: f64,
}

// 坏
struct Bar {
    short:       f64,
    really_long: f64,
}

// 好
let a = 0;
let radius = 7;

// 坏
let b        = 0;
let diameter = 7;

避免块注释

使用行注释:

// 等待主线程返回,并设置过程错误码
// 明显地。

而不是:

/*
 * 等待主线程返回,并设置过程错误码
 * 明显地。
 */

文档注释

总结行

任何文档注释中的第一行应该是一行总结代码的单行短句。该行用于在 Rustdoc 输出中的一个简短的总结性描述,所以,让它短比较好。

句子结构

所有的文档注释,包括总结行,一个以大写字母开始,以句号、问号,或者感叹号结束。最好使用完整的句子而不是片段。

例如:

/// 根据编译器提供的参数,设置一个缺省的运行时配置。
///
/// 这个函数将阻塞直到整个 M:N 调度器池退出了。
/// 这个函数也要求一个本地的线程可用。
///
/// # 参数
///
/// * `argc` 和 `argv` - 参数向量。在 Unix 系统上,该信息被`os::args`使用。
///
/// * `main` - 运行在 M:N 调度器池内的初始过程。
///            一旦这个过程退出,调度池将开始关闭。
///            整个池(和这个函数)将只有在所有子线程完成执行后。
///
/// # 返回值
///
/// 返回值被用作进程返回码。成功是 0,101 是错误。

避免文档内注释

内嵌文档注释 只用于 注释 crates 和文件级的模块:

//! 核心库。
//!
//! 核心库是...

解释上下文

Rust 没有特定的构造器,只有返回新实例的函数。 这些在自动生成的类型文档中是不可见的,因此你应该专门链接到它们:

/// An iterator that yields `None` forever after the underlying iterator
/// yields `None` once.
///
/// These can be created through
/// [`iter.fuse()`](trait.Iterator.html#method.fuse).
pub struct Fuse<I> {
    // ...
}

开始的大括号总是出现的同一行。

fn foo() {
    ...
}

fn frobnicate(a: Bar, b: Bar,
              c: Bar, d: Bar)
              -> Bar {
    ...
}

trait Bar {
    fn baz(&self);
}

impl Bar for Baz {
    fn baz(&self) {
        ...
    }
}

frob(|x| {
    x.transpose()
})

match 分支有大括号,除非是单行表达式。

match foo {
    bar => baz,
    quux => {
        do_something();
        do_something_else()
    }
}

return 语句有分号。

fn foo() {
    do_something();

    if condition() {
        return;
    }

    do_something_else();
}

行尾的逗号

Foo { bar: 0, baz: 1 }

Foo {
    bar: 0,
    baz: 1,
}

match a_thing {
    None => 0,
    Some(x) => 1,
}

一般命名约定

通常,Rust 倾向于为“类型级”结构(类型和 traits)使用 CamelCase 而为“值级”结构使用 snake_case 。更确切的约定:

条目

约定

Crates

snake_case (但倾向于单个词)

Modules

snake_case

Types

CamelCase

Traits

CamelCase

Enum variants

CamelCase

Functions

snake_case

Methods

snake_case

General constructors

new 或 with_more_details

Conversion constructors

from_some_other_type

Local variables

snake_case

Static variables

SCREAMING_SNAKE_CASE

Constant variables

SCREAMING_SNAKE_CASE

Type parameters

简洁 CamelCase,通常单个大写字母:T

Lifetimes

短的小写: 'a

在 CamelCase中, 首字母缩略词被当成一个单词:用 Uuid 而不是 UUID。在 snake_case 中,首字母缩略词全部是小写: is_xid_start。

在 snake_case 或 SCREAMING_SNAKE_CASE 中,“单词”永远不应该只包含一个字母, 除非是最后一个“单词”。所以,我们有btree_map 而不是 b_tree_map,PI_2 而不是 PI2。

引用函数/方法名中的类型

函数名经常涉及类型名,最常见的约定例子像 as_slice。如果类型有一个纯粹的文本名字(忽略参数), 在类型约定和函数约定之间转换是直截了当的:

类型名

方法中的文本

String

string

Vec<T>

vec

YourType

your_type

涉及记号的类型遵循以下约定。这些规则有重叠;应用最适用的规则:

类型名

方法中的文本

&str

str

&[T]

slice

&mut [T]

mut_slice

&[u8]

bytes

&T

ref

&mut T

mut

*const T

ptr

*mut T

mut_ptr

避免冗余的前缀

一个模块中的条目的名字不应拿模块的名字做前缀:

倾向于

mod foo {
    pub struct Error { ... }
}

而不是

mod foo {
    pub struct FooError { ... }
}

这个约定避免了口吃(像 io::IoError)。库客户端可以在导入时重命名以避免冲突。

Getter/setter 方法

一些数据类型不希望提供对它们的域的直接访问,但是提供了 "getter" 和 "setter" 方法用于操纵域状态 (经常提供检查或其他功能)。

域 foo: T 的约定是:

  • 方法 foo(&self) -> &T 用于获得该域的当前值。

  • 方法 set_foo(&self, val: T) 用于设置域。(这里的 val 参数可能取 &T 或其他类型,取决于上下文。)

请注意,这个约定是关于通常数据类型的 getters/setters, 不是 关于构建者对象的。

断言

  • 简单的布尔断言应该加上 is_ 或者其他的简短问题单词作为前缀,e.g., is_empty。

  • 常见的例外: lt, gt,和其他已经确认的断言名。

导入

一个 crate/模块的导入应该按顺序包括下面各个部分,之间以空行分隔:

  • extern crate 指令

  • 外部 use 导入

  • 本地 use 导入

  • pub use 导入

例如:

// Crates.
extern crate getopts;
extern crate mylib;

// 标准库导入。
use getopts::{optopt, getopts};
use std::os;

// 从一个我们写的库导入。
use mylib::webserver;

// 当我们导入这个模块时会被重新导出。
pub use self::types::Webdata;

避免 use *,除非在测试里

Glob 导入有几个缺点:

  • 更难知道名字在哪里绑定。

  • 它们前向不兼容,因为新的上流导出可能与现存的名字冲突。

在写 test 子模块时,为方便导入 super::* 是合适的。

当模块限定函数时,倾向于完全导入类型/traits。

例如:

use option::Option;
use mem;

let i: isize = mem::transmute(Option(0));

在 crate 级重新导出最重要的类型。

Crates pub use 最常见的类型为方便,因此,客户端不必记住或写 crate 的模块结构以使用这些类型。

类型和操作在一起定义。

类型定义和使用它们的函数/模块应该在同一模块中定义,类型出现在函数/模块前面。

Previous评测 (benchmark)NextAny与反射

Last updated 5 years ago

Was this helpful?

文档注释前面加三个斜线(///)而且提示你希望将注释包含在 Rustdoc 的输出里。 它们支持 而且是注释你的公开API的主要方式。

支持的 markdown 功能包括列在 文档中的所有扩展,加上上角标。

总结行应该以 来写。 基本上,这意味着用 "Returns" 而不是 "Return"。

Markdown 语言
GitHub Flavored Markdown
第三人称单数陈述句形式