程序项
程序项(item,简称项)包括模块顶层允许使用的一系列内容。不过,Rust 也允许某些程序项出现在其他类型的程序项中,如函数中。无论程序项是出现在模块层还是出现在其他程序项中,都适用相同的格式约定。
extern crate
语句必须放在文件的首位。它们必须按字母顺序排列。
use
语句和模块声明(mod foo;
,而不是 mod { ... }
)必须放在其他程序项之前。将导入放在模块声明之前。按字母顺序排序,但 self
和 super
必须排在其他名称之前。
不要自动移动注有 #[macro_use]
的模块声明,因为这可能会改变语义。
函数定义
在 Rust 中,人们经常通过搜索 fn [function-name]
来查找函数,因此函数定义的格式必须能够满足这一点。
正确的排序和空格位置是:
[pub] [unsafe] [extern ["ABI"]] fn foo(arg1: i32, arg2: i32) -> i32 {
...
}
避免在签名本身中添加注释。
如果函数签名不能放在一行内,则在开头括号后和结尾括号前分隔,并将每个参数放在自己的缩进行内。例如:
fn foo(
arg1: i32,
arg2: i32,
) -> i32 {
...
}
注意最后一个参数后面的逗号。
元组和元组结构
像编写函数的参数列表一样编写类型列表。
像调用函数一样构建元组或元组结构体。
单行
struct Bar(Type1, Type2);
let x = Bar(11, 22);
let y = (11, 22, 33);
Enums
In the declaration, put each variant on its own line, block indented.
Format each variant accordingly as either a struct (but without the struct
keyword), a tuple struct, or an identifier (which doesn't require special
formatting):
enum FooBar {
First(u32),
Second,
Error {
err: Box<Error>,
line: u32,
},
}
If a struct variant is small, format it on one line. In this case, do not use a trailing comma for the field list, but do put spaces around each brace:
enum FooBar {
Error { err: Box<Error>, line: u32 },
}
In an enum with multiple struct variants, if any struct variant is written on multiple lines, use the multi-line formatting for all struct variants. However, such a situation might be an indication that you should factor out the fields of the variant into their own struct.
Structs and Unions
Struct names follow on the same line as the struct
keyword, with the opening
brace on the same line when it fits within the right margin. All struct fields
are indented once and end with a trailing comma. The closing brace is not
indented and appears on its own line.
struct Foo {
a: A,
b: B,
}
If and only if the type of a field does not fit within the right margin, it is pulled down to its own line and indented again.
struct Foo {
a: A,
long_name:
LongType,
}
Prefer using a unit struct (e.g., struct Foo;
) to an empty struct (e.g.,
struct Foo();
or struct Foo {}
, these only exist to simplify code
generation), but if you must use an empty struct, keep it on one line with no
space between the braces: struct Foo;
or struct Foo {}
.
The same guidelines are used for untagged union declarations.
union Foo {
a: A,
b: B,
long_name:
LongType,
}
Tuple structs
Put the whole struct on one line if possible. Separate types within the parentheses using a comma and space. Don't use a trailing comma for a single-line tuple struct. Don't put spaces around the parentheses or semicolon:
pub struct Foo(String, u8);
Prefer unit structs to empty tuple structs (these only exist to simplify code
generation), e.g., struct Foo;
rather than struct Foo();
.
For more than a few fields (in particular if the tuple struct does not fit on one line), prefer a proper struct with named fields.
For a multi-line tuple struct, block-format the fields with a field on each line and a trailing comma:
pub struct Foo(
String,
u8,
);
Traits
Use block-indent for trait items. If there are no items, format the trait (including its {}
)
on a single line. Otherwise, break after the opening brace and before
the closing brace:
trait Foo {}
pub trait Bar {
...
}
If the trait has bounds, put a space after the colon but not before,
and put spaces around each +
, e.g.,
trait Foo: Debug + Bar {}
Prefer not to line-break in the bounds if possible (consider using a where
clause). Prefer to break between bounds than to break any individual bound. If
you must break the bounds, put each bound (including the first) on its own
block-indented line, break before the +
and put the opening brace on its own
line:
pub trait IndexRanges:
Index<Range<usize>, Output=Self>
+ Index<RangeTo<usize>, Output=Self>
+ Index<RangeFrom<usize>, Output=Self>
+ Index<RangeFull, Output=Self>
{
...
}
Impls
Use block-indent for impl items. If there are no items, format the impl
(including its {}
) on a single line. Otherwise, break after the opening brace
and before the closing brace:
impl Foo {}
impl Bar for Foo {
...
}
Avoid line-breaking in the signature if possible. If a line break is required in
a non-inherent impl, break immediately before for
, block indent the concrete type
and put the opening brace on its own line:
impl Bar
for Foo
{
...
}
Extern crate
extern crate foo;
Use spaces around keywords, no spaces around the semicolon.
Modules
mod foo {
}
mod foo;
Use spaces around keywords and before the opening brace, no spaces around the semicolon.
macro_rules!
Use {}
for the full definition of the macro.
macro_rules! foo {
}
Generics
Prefer to put a generics clause on one line. Break other parts of an item
declaration rather than line-breaking a generics clause. If a generics clause is
large enough to require line-breaking, prefer a where
clause instead.
Do not put spaces before or after <
nor before >
. Only put a space after
>
if it is followed by a word or opening brace, not an opening parenthesis.
Put a space after each comma. Do not use a trailing comma for a single-line
generics clause.
fn foo<T: Display, U: Debug>(x: Vec<T>, y: Vec<U>) ...
impl<T: Display, U: Debug> SomeType<T, U> { ...
If the generics clause must be formatted across multiple lines, put each
parameter on its own block-indented line, break after the opening <
and
before the closing >
, and use a trailing comma.
fn foo<
T: Display,
U: Debug,
>(x: Vec<T>, y: Vec<U>) ...
If an associated type is bound in a generic type, put spaces around the =
:
<T: Example<Item = u32>>
Prefer to use single-letter names for generic parameters.
where
clauses
These rules apply for where
clauses on any item.
If immediately following a closing bracket of any kind, write the keyword
where
on the same line, with a space before it.
Otherwise, put where
on a new line at the same indentation level. Put each
component of a where
clause on its own line, block-indented. Use a trailing
comma, unless the clause is terminated with a semicolon. If the where
clause
is followed by a block (or assignment), start that block on a new line.
Examples:
fn function<T, U>(args)
where
T: Bound,
U: AnotherBound,
{
body
}
fn foo<T>(
args
) -> ReturnType
where
T: Bound,
{
body
}
fn foo<T, U>(
args,
) where
T: Bound,
U: AnotherBound,
{
body
}
fn foo<T, U>(
args
) -> ReturnType
where
T: Bound,
U: AnotherBound; // Note, no trailing comma.
// Note that where clauses on `type` aliases are not enforced and should not
// be used.
type Foo<T>
where
T: Bound
= Bar<T>;
If a where
clause is very short, prefer using an inline bound on the type
parameter.
If a component of a where
clause does not fit and contains +
, break it
before each +
and block-indent the continuation lines. Put each bound on its
own line. E.g.,
impl<T: ?Sized, Idx> IndexRanges<Idx> for T
where
T: Index<Range<Idx>, Output = Self::Output>
+ Index<RangeTo<Idx>, Output = Self::Output>
+ Index<RangeFrom<Idx>, Output = Self::Output>
+ Index<RangeInclusive<Idx>, Output = Self::Output>
+ Index<RangeToInclusive<Idx>, Output = Self::Output>
+ Index<RangeFull>,
Type aliases
Keep type aliases on one line when they fit. If necessary to break the line, do
so after the =
, and block-indent the right-hand side:
pub type Foo = Bar<T>;
// If multi-line is required
type VeryLongType<T, U: SomeBound> =
AnEvenLongerType<T, U, Foo<T>>;
Where possible avoid where
clauses and keep type constraints inline. Where
that is not possible split the line before and after the where
clause (and
split the where
clause as normal), e.g.,
type VeryLongType<T, U>
where
T: U::AnAssociatedType,
U: SomeBound,
= AnEvenLongerType<T, U, Foo<T>>;
Associated types
Format associated types like type aliases. Where an associated type has a bound, put a space after the colon but not before:
pub type Foo: Bar;
extern items
When writing extern items (such as extern "C" fn
), always specify the ABI.
For example, write extern "C" fn foo ...
, not extern fn foo ...
, or
extern "C" { ... }
.
Imports (use
statements)
Format imports on one line where possible. Don't put spaces around braces.
use a::b::c;
use a::b::d::*;
use a::b::{foo, bar, baz};
Large list imports
Prefer to use multiple imports rather than a multi-line import. However, tools should not split imports by default.
If an import does require multiple lines (either because a list of single names does not fit within the max width, or because of the rules for nested imports below), then break after the opening brace and before the closing brace, use a trailing comma, and block indent the names.
// Prefer
foo::{long, list, of, imports};
foo::{more, imports};
// If necessary
foo::{
long, list, of, imports, more,
imports, // Note trailing comma
};
Ordering of imports
A group of imports is a set of imports on the same or sequential lines. One or more blank lines or other items (e.g., a function) separate groups of imports.
Within a group of imports, imports must be sorted ASCIIbetically (uppercase before lowercase). Groups of imports must not be merged or re-ordered.
E.g., input:
use d;
use c;
use b;
use a;
output:
use c;
use d;
use a;
use b;
Because of macro_use
, attributes must also start a new group and prevent
re-ordering.
Ordering list import
Names in a list import must be sorted ASCIIbetically, but with self
and
super
first, and groups and glob imports last. This applies recursively. For
example, a::*
comes before b::a
but a::b
comes before a::*
. E.g.,
use foo::bar::{a, b::c, b::d, b::d::{x, y, z}, b::{self, r, s}};
.
Normalisation
Tools must make the following normalisations, recursively:
use a::self;
->use a;
use a::{};
-> (nothing)use a::{b};
->use a::b;
Tools must not otherwise merge or un-merge import lists or adjust glob imports (without an explicit option).
Nested imports
If there are any nested imports in a list import, then use the multi-line form, even if the import fits on one line. Each nested import must be on its own line, but non-nested imports must be grouped on as few lines as possible.
For example,
use a::b::{
x, y, z,
u::{...},
w::{...},
};
Merging/un-merging imports
An example:
// Un-merged
use a::b;
use a::c::d;
// Merged
use a::{b, c::d};
Tools must not merge or un-merge imports by default. They may offer merging or un-merging as an option.