-
Notifications
You must be signed in to change notification settings - Fork 0
Note style guide
Here are some rough guidelines to Rust style. They are followed unevenly and there's not necessarily a consensus about everything in here. More work is required.
- Lines should not be longer than 100 characters.
- Use spaces for indentation, not tabs.
- Key-value attributes should have spaces around the equals sign:
#[foo = "bar"]
- Type names and enumeration variants should be in
CamelCase
. - Acronyms should be camel case, too:
Uuid
, notUUID
. - Functions, methods, and variables should be
lowercase_with_underscores
where it helps readability. - Static variables should be in
ALL_CAPS
. - Constructors should be methods called
new
ornew_with_more_details
. - Constructors that simply convert from another type should be methods called
from_foo
. - When writing a binding to an external library, put the raw C bindings in a module called
ffi
(rather thanll
). Do not create high-level bindings calledhl
. - lifetime names should be lowercase and are often simply
'a
.
- trait examples: Copy, Owned, Const, Add, Sub, Num, Shr, Index, Encode, Decode, Reader, Writer, GenericPath
- extension traits: FooUtil. However, prefer default methods to extension traits.
- avoid words with suffixes (able, etc). Try to use transitive verbs, nouns, and then adjectives in that order.
Functions for converting between types should attempt to follow this:
-
as
: cheap conversions that are normally just converting a reference to a different type, but not changing the in-memory representation, e.g.string.as_bytes()
gives a&[u8]
view into a&str
. These don't consume the convertee. -
to
: expensive conversions that may allocate and copy data, e.g.string.to_owned()
copies a&str
to a new~str
. These also don't consume the convertee. -
into
: conversions that consume the convertee and almost always don't allocate new memory (they may change the in-memory representation, but will normally do so in-place), these are cheaper thanto
conversions, e.g.string.into_bytes()
converts a~str
to a~[u8]
without copying.
These are not hard rules, since generically implemented functions mean that an into
conversion that doesn't copy/allocate is impossible for some types, e.g. string.into_owned()
(from the Str
trait) doesn't copy when string
is ~str
, but it is forced to when string
is &str
or @str
.
Naming iterators is often a little tricky because their names can get quite verbose very quickly. Since #11001 landed, we've standardized iterator naming conventions. When naming an iterator, follow these rules from top-to bottom (short circuiting when you hit a relevant one).
- If the iterator yields something that can be described with a noun, the iterator should be called the pluralization of that noun (e.g. an iterator yielding words is called Words)
- An iterator over the members of a container should have a base name of
Items
, with different flavors deriving from this name. Different flavors are applied top-to-bottom from this list
- Moving iterators have a prefix of
Move
- If the default iterator yields an immutable reference, an iterator yielding a mutable reference has a prefix
Mut
- Reverse iterators have a prefix of
Rev
- If these rules would result in a name that might cause confusion, pick a less confusing name.
These rules are a little vague, and that's partly on purpose. The general idea is to be concise and consistent. Examples through libstd and libextra should showcase how we expect iterators to be named.
Wrapped functions:
fn frobnicate(a: Bar,
b: Bar)
-> Bar {
code;
}
fn foo<T:This,
U:That>(
a: Bar,
b: Bar)
-> Baz {
code;
}
(Note: We need to adjust editors to do this automatically. This is not the current convention.)
The downside of this is, that the indentation level of many lines of code may change when the length of a function name changes.
- When writing cross-platform code, try to group platform-specific code into a module called
platform
. - Try to avoid
#[cfg]
directives outside thisplatform
module.
- Write
extern crate
directives first, then a blank line. - Put local imports first, then external imports, then
pub use
. - Avoid using
use *
, except in tests.
Prefer fully importing types while module-qualifying functions, e.g.
use option::Option;
use cast;
let i: int = cast::transmute(Option(0));
-
It's OK to use
foo = bar;
-
Avoid importing functions, unless they're very common. Instead import up to the module you're going to use and then call
mod::func()
.
- Put tests in a test module at the bottom of the modules they test.
- Use
#[cfg(test)]
to only compile when testing. Example:
#[cfg(test)]
mod test {
}
Dereference the match target if you can. Prefer
match *foo {
X(...) => ...
Y(...) => ...
}
over
match foo {
&X(...) => ...
&Y(...) => ...
}
If you have multiple patterns in a single arm, prefer
match foo {
bar(*)
| baz => quux,
x
| y
| z => {
quuux
}
}
Only omit braces for single expressions.
match foo {
bar => baz,
quux => {
do_something();
do_something_else();
}
}
Prefer line comments and avoid block comments. This avoids the debate about whether to put stars on every line, etc.
In doc comments, write sentences that begin with capital letters and end in a period, even in the short summary description. Avoid fragments.
Favor outer doc comments:
/// Function documentation.
fn foo() {
...
}
Only use inner doc comments to document crates and file-level modules:
//! The core library.
//!
//! The core library is a something something...
Use full sentences that start with capitals and end with a period. See Doc-using-rustdoc.
Put types first, then implementations.
TODO
TODO
- Do not blame the user: avoid addressing the user directly with phrases like "did you forget ...?"
- Rust code in error messages should be enclosed in backquotes.
For instance:
found `true` in restricted position
Error messages should use the pattern "expected `X`, found `Y`".
mismatched types: expected `u16`, found `u8`
The names of simple boolean predicates should start with "is_" or similarly be expressed using a "small question word".
The notable exceptions are generally established predicate names like "lt", "ge", etc.
Examples:
is_not_empty
A for
loop is always preferable to a while
loop unless the loop counts in a non-uniform way (making it difficult to express as a for
).
- Do we want to prefer 'top-down' organization?
- Prefer unsafe pointers to unsafely transmuting borrowed pointers
All Categories:
- Docs -- For users
- Notes -- For developers
- Libs -- For library authors
- Meeting minutes