Contents

Appendix — Appendices A–G

Appendix

Appendices A–G


The following sections contain reference material you may find useful in your Rust journey: the keyword and symbol tables, the traits you can derive, the tools that ship with Rust, how editions work, translations of the book, and how Rust itself is made.

  • A Keywords
  • B Operators and Symbols
  • C Derivable Traits
  • D Useful Development Tools
  • E Editions
  • F Translations of the Book
  • G How Rust is Made and “Nightly Rust”

The Rust Programming Language · Appendix

1

Appendix · A Keywords

Keywords are reserved words

The following lists contain keywords that are reserved for current or future use by the Rust language. As such, they cannot be used as identifiers — except as raw identifiers, discussed in “Raw Identifiers” at the end of this appendix.

Definition A.1 (Identifier). A name of a function, variable, parameter, struct field, module, crate, constant, macro, static value, attribute, type, trait, or lifetime.

Appendix A has three parts:

  • Keywords currently in use — each listed with its functionality (Table A.1, four slides).
  • Keywords reserved for future use — no functionality yet (Table A.2).
  • Raw identifiers — the r# syntax that lets you use a keyword as an identifier.

The Rust Programming Language · Appendix

2

Appendix · A Keywords

Keywords currently in use (1 of 4): as – enum

Table A.1: Keywords currently in use, with their functionality

KeywordFunctionality
asPerform primitive casting, disambiguate the specific trait containing an item, or rename items in use statements
asyncReturn a Future instead of blocking the current thread
awaitSuspend execution until the result of a Future is ready
breakExit a loop immediately
constDefine constant items or constant raw pointers
continueContinue to the next loop iteration
crateIn a module path, refers to the crate root
dynDynamic dispatch to a trait object
elseFallback for if and if let control flow constructs
enumDefine an enumeration

The Rust Programming Language · Appendix

3

Appendix · A Keywords

Keywords currently in use (2 of 4): extern – match

Table A.1 (continued): Keywords currently in use, with their functionality

KeywordFunctionality
externLink an external function or variable
falseBoolean false literal
fnDefine a function or the function pointer type
forLoop over items from an iterator, implement a trait, or specify a higher ranked lifetime
ifBranch based on the result of a conditional expression
implImplement inherent or trait functionality
inPart of for loop syntax
letBind a variable
loopLoop unconditionally
matchMatch a value to patterns

The Rust Programming Language · Appendix

4

Appendix · A Keywords

Keywords currently in use (3 of 4): mod – struct

Table A.1 (continued): Keywords currently in use, with their functionality

KeywordFunctionality
modDefine a module
moveMake a closure take ownership of all its captures
mutDenote mutability in references, raw pointers, or pattern bindings
pubDenote public visibility in struct fields, impl blocks, or modules
refBind by reference
returnReturn from function
SelfA type alias for the type we are defining or implementing
selfMethod subject or current module
staticGlobal variable or lifetime lasting the entire program execution
structDefine a structure

The Rust Programming Language · Appendix

5

Appendix · A Keywords

Keywords currently in use (4 of 4): super – while

Table A.1 (continued): Keywords currently in use, with their functionality

KeywordFunctionality
superParent module of the current module
traitDefine a trait
trueBoolean true literal
typeDefine a type alias or associated type
unionDefine a union; is a keyword only when used in a union declaration
unsafeDenote unsafe code, functions, traits, or implementations
useBring symbols into scope
whereDenote clauses that constrain a type
whileLoop conditionally based on the result of an expression

Remark. union is a contextual keyword: outside a union declaration it can still be used as an ordinary identifier. See the Rust Reference, “Unions”.

The Rust Programming Language · Appendix

6

Appendix · A Keywords

Keywords reserved for future use

The following keywords do not yet have any functionality but are reserved by Rust for potential future use. Like the keywords in use, they cannot be ordinary identifiers.

Table A.2: Keywords reserved for future use (14 keywords)

Reserved keywordReserved keyword
abstractoverride
becomepriv
boxtry
dotypeof
finalunsized
genvirtual
macroyield

The Rust Programming Language · Appendix

7

Appendix · A Keywords

Raw identifiers: the problem

Definition A.2 (Raw identifier). The syntax that lets you use keywords where they wouldn’t normally be allowed: you prefix a keyword with r#.

For example, match is a keyword. Try to compile a function that uses match as its name:

src/main.rs

fn match(needle: &str, haystack: &str) -> bool {

    haystack.contains(needle)

}

You’ll get this error:

error: expected identifier, found keyword `match`

 --> src/main.rs:4:4

  |

4 | fn match(needle: &str, haystack: &str) -> bool {

  |    ^^^^^ expected identifier, found keyword

The error shows that you can’t use the keyword match as the function identifier. To use match as a function name, you need the raw identifier syntax.

The Rust Programming Language · Appendix

8

Appendix · A Keywords

Raw identifiers: the fix, and why they exist

src/main.rs

fn r#match(needle: &str, haystack: &str) -> bool {

    haystack.contains(needle)

}

 

fn main() {

    assert!(r#match("foo", "foobar"));

}

This code compiles without any errors. Note the r# prefix on the function name both in its definition and where the function is called in main.

Raw identifiers let you use any word you choose as an identifier, even a reserved keyword. That gives more freedom in naming and lets Rust integrate with programs written in a language where these words aren’t keywords.

Example A.3. Raw identifiers also let you use libraries written in a different Rust edition than your crate. try isn’t a keyword in the 2015 edition but is in the 2018, 2021, and 2024 editions. If you depend on a 2015-edition library that has a try function, you call it as r#try from your code on later editions. (Editions: Appendix E.)

The Rust Programming Language · Appendix

9

Appendix · B Operators and Symbols

A glossary of Rust’s syntax

This appendix contains a glossary of Rust’s syntax, including operators and other symbols that appear by themselves or in the context of paths, generics, trait bounds, macros, attributes, comments, tuples, and brackets.

Operators

Table A.3 (the book’s Table B-1, next six slides) lists the operators in Rust, an example of how each operator would appear in context, a short explanation, and whether that operator is overloadable. If an operator is overloadable, the relevant trait to use to overload that operator is listed.

Example A.4. The row for + in expr + expr names the trait Add: implement std::ops::Add for your type and a + b works on it. Rows with an empty last cell (such as &&) cannot be overloaded.

The non-operator symbols follow in Tables A.4–A.12 (the book’s Tables B-2 to B-10).

The Rust Programming Language · Appendix

10

Appendix · B Operators and Symbols

Operators (1 of 6): ! to &&

Table A.3: Operators (book Table B-1) — “—” means not overloadable

OperatorExampleExplanationOverloadable?
!ident!(...), ident!{...}, ident![...]Macro expansion—
!!exprBitwise or logical complementNot
!=expr != exprNonequality comparisonPartialEq
%expr % exprArithmetic remainderRem
%=var %= exprArithmetic remainder and assignmentRemAssign
&&expr, &mut exprBorrow—
&&type, &mut type, &'a type, &'a mut typeBorrowed pointer type—
&expr & exprBitwise ANDBitAnd
&=var &= exprBitwise AND and assignmentBitAndAssign
&&expr && exprShort-circuiting logical AND—

The Rust Programming Language · Appendix

11

Appendix · B Operators and Symbols

Operators (2 of 6): * to -

Table A.3 (continued): Operators (book Table B-1)

OperatorExampleExplanationOverloadable?
*expr * exprArithmetic multiplicationMul
*=var *= exprArithmetic multiplication and assignmentMulAssign
**exprDereferenceDeref
**const type, *mut typeRaw pointer—
+trait + trait, 'a + traitCompound type constraint—
+expr + exprArithmetic additionAdd
+=var += exprArithmetic addition and assignmentAddAssign
,expr, exprArgument and element separator—
-- exprArithmetic negationNeg
-expr - exprArithmetic subtractionSub

The Rust Programming Language · Appendix

12

Appendix · B Operators and Symbols

Operators (3 of 6): -= to ..

Table A.3 (continued): Operators (book Table B-1)

OperatorExampleExplanationOverloadable?
-=var -= exprArithmetic subtraction and assignmentSubAssign
->fn(...) -> type, |…| -> typeFunction and closure return type—
.expr.identField access—
.expr.ident(expr, ...)Method call—
.expr.0, expr.1, and so onTuple indexing—
...., expr.., ..expr, expr..exprRight-exclusive range literalPartialOrd
..=..=expr, expr..=exprRight-inclusive range literalPartialOrd
....exprStruct literal update syntax—
..variant(x, ..), struct_type { x, .. }“And the rest” pattern binding—

The Rust Programming Language · Appendix

13

Appendix · B Operators and Symbols

Operators (4 of 6): ... to <<

Table A.3 (continued): Operators (book Table B-1)

OperatorExampleExplanationOverloadable?
...expr...expr(Deprecated, use ..= instead) In a pattern: inclusive range pattern—
/expr / exprArithmetic divisionDiv
/=var /= exprArithmetic division and assignmentDivAssign
:pat: type, ident: typeConstraints—
:ident: exprStruct field initializer—
:'a: loop {...}Loop label—
;expr;Statement and item terminator—
;[...; len]Part of fixed-size array syntax—
<<expr << exprLeft-shiftShl

The Rust Programming Language · Appendix

14

Appendix · B Operators and Symbols

Operators (5 of 6): <<= to >>

Table A.3 (continued): Operators (book Table B-1)

OperatorExampleExplanationOverloadable?
<<=var <<= exprLeft-shift and assignmentShlAssign
<expr < exprLess than comparisonPartialOrd
<=expr <= exprLess than or equal to comparisonPartialOrd
=var = expr, ident = typeAssignment/equivalence—
==expr == exprEquality comparisonPartialEq
=>pat => exprPart of match arm syntax—
>expr > exprGreater than comparisonPartialOrd
>=expr >= exprGreater than or equal to comparisonPartialOrd
>>expr >> exprRight-shiftShr

The Rust Programming Language · Appendix

15

Appendix · B Operators and Symbols

Operators (6 of 6): >>= to ?

Table A.3 (continued): Operators (book Table B-1)

OperatorExampleExplanationOverloadable?
>>=var >>= exprRight-shift and assignmentShrAssign
@ident @ patPattern binding—
^expr ^ exprBitwise exclusive ORBitXor
^=var ^= exprBitwise exclusive OR and assignmentBitXorAssign
|pat | patPattern alternatives—
|expr | exprBitwise ORBitOr
|=var |= exprBitwise OR and assignmentBitOrAssign
||expr || exprShort-circuiting logical OR—
?expr?Error propagation—

The Rust Programming Language · Appendix

16

Appendix · B Operators and Symbols

Non-operator symbols: stand-alone syntax (1 of 2)

The following tables contain all symbols that don’t function as operators; that is, they don’t behave like a function or method call. Table A.4 shows symbols that appear on their own and are valid in a variety of locations.

Table A.4: Stand-alone syntax (book Table B-2)

SymbolExplanation
'identNamed lifetime or loop label
Digits immediately followed by u8, i32, f64, usize, and so onNumeric literal of specific type
"..."String literal
r"...", r#"..."#, r##"..."##, and so onRaw string literal; escape characters not processed
b"..."Byte string literal; constructs an array of bytes instead of a string
br"...", br#"..."#, br##"..."##, and so onRaw byte string literal; combination of raw and byte string literal

The Rust Programming Language · Appendix

17

Appendix · B Operators and Symbols

Non-operator symbols: stand-alone syntax (2 of 2)

Table A.4 (continued): Stand-alone syntax (book Table B-2)

SymbolExplanation
'...'Character literal
b'...'ASCII byte literal
|…| exprClosure
!Always-empty bottom type for diverging functions
_“Ignored” pattern binding; also used to make integer literals readable

Example A.5. A few stand-alone symbols in use: a typed numeric literal made readable with _, a raw string, a byte string, and a closure.

let big = 1_000_000u32;

let path = r"C:\no\escapes";

let bytes = b"abc";

let double = |x: i32| x * 2;

The Rust Programming Language · Appendix

18

Appendix · B Operators and Symbols

Path-related syntax

Table A.5: Path-related syntax (book Table B-3) — symbols that appear in the context of a path through the module hierarchy to an item

SymbolExplanation
ident::identNamespace path
::pathPath relative to the crate root (that is, an explicitly absolute path)
self::pathPath relative to the current module (that is, an explicitly relative path)
super::pathPath relative to the parent of the current module
type::ident, <type as trait>::identAssociated constants, functions, and types
<type>::...Associated item for a type that cannot be directly named (for example, <&T>::..., <[T]>::..., and so on)
trait::method(...)Disambiguating a method call by naming the trait that defines it
type::method(...)Disambiguating a method call by naming the type for which it’s defined
<type as trait>::method(...)Disambiguating a method call by naming the trait and type

The Rust Programming Language · Appendix

19

Appendix · B Operators and Symbols

Generics syntax

Table A.6: Generics (book Table B-4) — symbols that appear in the context of using generic type parameters

SymbolExplanation
path<...>Specifies parameters to a generic type in a type (for example, Vec<u8>)
path::<...>, method::<...>Specifies parameters to a generic type, function, or method in an expression; often referred to as turbofish (for example, "42".parse::<i32>())
fn ident<...> ...Define generic function
struct ident<...> ...Define generic structure
enum ident<...> ...Define generic enumeration
impl<...> ...Define generic implementation
for<...> typeHigher ranked lifetime bounds
type<ident=type>A generic type where one or more associated types have specific assignments (for example, Iterator<Item=T>)

The Rust Programming Language · Appendix

20

Appendix · B Operators and Symbols

Trait bound constraints

Table A.7 shows symbols that appear in the context of constraining generic type parameters with trait bounds.

Table A.7: Trait bound constraints (book Table B-5)

SymbolExplanation
T: UGeneric parameter T constrained to types that implement U
T: 'aGeneric type T must outlive lifetime 'a (meaning the type cannot transitively contain any references with lifetimes shorter than 'a)
T: 'staticGeneric type T contains no borrowed references other than 'static ones
'b: 'aGeneric lifetime 'b must outlive lifetime 'a
T: ?SizedAllow generic type parameter to be a dynamically sized type
'a + trait, trait + traitCompound type constraint

The Rust Programming Language · Appendix

21

Appendix · B Operators and Symbols

Macros, attributes and comments

Symbols that appear in the context of calling or defining macros and specifying attributes on an item:

Table A.8: Macros and attributes (book Table B-6)

SymbolExplanation
#[meta]Outer attribute
#![meta]Inner attribute
$identMacro substitution
$ident:kindMacro metavariable
$(...)...Macro repetition
ident!(...), ident!{...}, ident![...]Macro invocation

Symbols that create comments:

Table A.9: Comments (book Table B-7)

SymbolExplanation
//Line comment
//!Inner line doc comment
///Outer line doc comment
/*...*/Block comment
/*!...*/Inner block doc comment
/**...*/Outer block doc comment

The Rust Programming Language · Appendix

22

Appendix · B Operators and Symbols

Parentheses and curly brackets

Table A.10: Parentheses (book Table B-8) — the contexts in which parentheses are used

SymbolExplanation
()Empty tuple (aka unit), both literal and type
(expr)Parenthesized expression
(expr,)Single-element tuple expression
(type,)Single-element tuple type
(expr, ...)Tuple expression
(type, ...)Tuple type
expr(expr, ...)Function call expression; also used to initialize tuple structs and tuple enum variants

Table A.11: Curly brackets (book Table B-9) — the contexts in which curly brackets are used

ContextExplanation
{...}Block expression
Type {...}Struct literal

The Rust Programming Language · Appendix

23

Appendix · B Operators and Symbols

Square brackets

Table A.12: Square brackets (book Table B-10) — the contexts in which square brackets are used

ContextExplanation
[...]Array literal
[expr; len]Array literal containing len copies of expr
[type; len]Array type containing len instances of type
expr[expr]Collection indexing; overloadable (Index, IndexMut)
expr[..], expr[a..], expr[..b], expr[a..b]Collection indexing pretending to be collection slicing, using Range, RangeFrom, RangeTo, or RangeFull as the “index”

The Rust Programming Language · Appendix

24

Appendix · C Derivable Traits

The derive attribute

Definition A.6 (derive attribute). An attribute you apply to a struct or enum definition; it generates code that implements a trait, with its own default implementation, on the type you’ve annotated with the derive syntax.

This appendix is a reference of all the traits in the standard library that you can use with derive. Each section covers:

  • What operators and methods deriving this trait will enable
  • What the implementation of the trait provided by derive does
  • What implementing the trait signifies about the type
  • The conditions in which you’re allowed or not allowed to implement the trait
  • Examples of operations that require the trait

If you want different behavior from that provided by derive, consult the standard library documentation for each trait for details on how to implement it manually.

The Rust Programming Language · Appendix

25

Appendix · C Derivable Traits

Which traits can be derived — and which cannot

The traits listed here are the only ones defined by the standard library that can be implemented on your types using derive. Other standard library traits don’t have sensible default behavior, so it’s up to you to implement them in the way that makes sense for what you’re trying to accomplish.

Example A.7. Display, which handles formatting for end users, can’t be derived. You should always consider the appropriate way to display a type to an end user. What parts of the type should an end user be allowed to see? What parts would they find relevant? What format of the data would be most relevant to them? The Rust compiler doesn’t have this insight, so it can’t provide appropriate default behavior for you.

The list of derivable traits in this appendix is not comprehensive: libraries can implement derive for their own traits, making the list of traits you can use derive with truly open ended.

Remark. Implementing derive involves using a procedural macro, covered in the “Custom derive Macros” section in Chapter 20.

The Rust Programming Language · Appendix

26

Appendix · C Derivable Traits

Debug for programmer output

The Debug trait enables debug formatting in format strings, which you indicate by adding :? within {} placeholders.

Debug lets you print instances of a type for debugging purposes, so you and other programmers using your type can inspect an instance at a particular point in a program’s execution.

Required by: for example, the assert_eq! macro. It prints the values of the instances given as arguments if the equality assertion fails, so programmers can see why the two instances weren’t equal.

Example A.8. Deriving Debug and PartialEq (next slide) makes a struct printable and usable in assert_eq!.

#[derive(Debug, PartialEq)]

struct Point { x: i32, y: i32 }

let p = Point { x: 1, y: 2 };

println!("{p:?}");                // Point { x: 1, y: 2 }

assert_eq!(p, Point { x: 1, y: 2 });

The Rust Programming Language · Appendix

27

Appendix · C Derivable Traits

PartialEq and Eq for equality comparisons

PartialEq

Lets you compare instances of a type for equality and enables the == and != operators. Deriving it implements the eq method.

  • On structs: two instances are equal only if all fields are equal, and not equal if any field is not equal.
  • On enums: each variant is equal to itself and not equal to the other variants.

Required by: for example, assert_eq!, which must compare two instances for equality.

Eq

Has no methods. It signals that for every value of the annotated type, the value is equal to itself. Eq can only be applied to types that also implement PartialEq — but not all such types can implement Eq.

Floating-point types are one example: two instances of the not-a-number (NaN) value are not equal to each other.

Required by: keys in a HashMap<K, V>, so it can tell whether two keys are the same.

The Rust Programming Language · Appendix

28

Appendix · C Derivable Traits

PartialOrd for ordering comparisons

The PartialOrd trait lets you compare instances of a type for sorting purposes. A type that implements PartialOrd can be used with the <, >, <=, and >= operators. You can only apply PartialOrd to types that also implement PartialEq.

Deriving PartialOrd implements the partial_cmp method, which returns an Option<Ordering> that is None when the values given don’t produce an ordering. An example of a value that doesn’t produce an ordering, even though most values of its type can be compared, is the NaN floating-point value: calling partial_cmp with any floating-point number and NaN returns None.

  • On structs: compares two instances by comparing the value in each field, in the order the fields appear in the struct definition.
  • On enums: variants declared earlier in the enum definition are considered less than the variants listed later.

Required by: for example, the gen_range method from the rand crate, which generates a random value in the range specified by a range expression.

The Rust Programming Language · Appendix

29

Appendix · C Derivable Traits

Ord for total ordering

The Ord trait lets you know that for any two values of the annotated type, a valid ordering will exist. It implements the cmp method, which returns an Ordering rather than an Option<Ordering>, because a valid ordering is always possible.

You can only apply Ord to types that also implement PartialOrd and Eq (and Eq requires PartialEq). When derived on structs and enums, cmp behaves the same way as the derived partial_cmp does with PartialOrd.

Required by: storing values in a BTreeSet<T>, a data structure that stores data based on the sort order of the values.

Example A.9. A derived ordering on an enum follows declaration order, so the whole chain of traits is derived together:

#[derive(PartialEq, Eq, PartialOrd, Ord)]

enum Size { Small, Medium, Large }

assert!(Size::Small < Size::Large);  // declared earlier => less

The Rust Programming Language · Appendix

30

Appendix · C Derivable Traits

Clone for duplicating values

The Clone trait lets you explicitly create a deep copy of a value; the duplication process might involve running arbitrary code and copying heap data. (More on Clone: “Variables and Data Interacting with Clone”, Chapter 4.)

Deriving Clone implements the clone method, which, when implemented for the whole type, calls clone on each of the parts of the type. This means all the fields or values in the type must also implement Clone to derive Clone.

Required by: calling the to_vec method on a slice. The slice doesn’t own the type instances it contains, but the vector returned from to_vec needs to own its instances, so to_vec calls clone on each item. Thus, the type stored in the slice must implement Clone.

The Rust Programming Language · Appendix

31

Appendix · C Derivable Traits

Copy for duplicating values cheaply

The Copy trait lets you duplicate a value by only copying bits stored on the stack; no arbitrary code is necessary. (More on Copy: “Stack-Only Data: Copy”, Chapter 4.)

Copy doesn’t define any methods, to prevent programmers from overloading those methods and violating the assumption that no arbitrary code is being run. That way, all programmers can assume that copying a value will be very fast.

You can derive Copy on any type whose parts all implement Copy. A type that implements Copy must also implement Clone, because a Copy type has a trivial implementation of Clone that performs the same task as Copy.

Rarely required: types that implement Copy have optimizations available, meaning you don’t have to call clone, which makes the code more concise.

Remark. Everything possible with Copy you can also accomplish with Clone, but the code might be slower or have to use clone in places.

The Rust Programming Language · Appendix

32

Appendix · C Derivable Traits

Hash for mapping a value to a value of fixed size

The Hash trait lets you take an instance of a type of arbitrary size and map that instance to a value of fixed size using a hash function.

Deriving Hash implements the hash method. The derived implementation combines the result of calling hash on each of the parts of the type, meaning all fields or values must also implement Hash to derive Hash.

Required by: storing keys in a HashMap<K, V> to store data efficiently.

Example A.10. A type used as a HashMap key needs Hash plus Eq (and so PartialEq):

#[derive(PartialEq, Eq, Hash)]

struct UserId(u32);

let mut names: HashMap<UserId, String> = HashMap::new();

names.insert(UserId(7), String::from("Ferris"));

The Rust Programming Language · Appendix

33

Appendix · C Derivable Traits

Default for default values

The Default trait lets you create a default value for a type. Deriving Default implements the default function, whose derived implementation calls default on each part of the type — so all fields or values in the type must also implement Default to derive Default.

Default::default is commonly combined with the struct update syntax (“Creating Instances from Other Instances with Struct Update Syntax”, Chapter 5): customize a few fields of a struct, then set and use a default value for the rest with ..Default::default().

Required by: for example, the method unwrap_or_default on Option<T>. If the Option<T> is None, unwrap_or_default returns the result of Default::default for the type T stored in the Option<T>.

Example A.11. Struct update syntax with derived defaults:

#[derive(Default)]

struct Config { verbose: bool, retries: u32, name: String }

let c = Config { retries: 3, ..Default::default() };  // verbose: false, name: ""

The Rust Programming Language · Appendix

34

Appendix · D Useful Development Tools

Automatic formatting with rustfmt

This appendix covers useful development tools that the Rust project provides: automatic formatting, quick ways to apply warning fixes, a linter, and integration with IDEs.

The rustfmt tool reformats your code according to the community code style. Many collaborative projects use rustfmt to prevent arguments about which style to use when writing Rust: everyone formats their code using the tool.

Rust installations include rustfmt by default, so you should already have the programs rustfmt and cargo-fmt. They are analogous to rustc and cargo: rustfmt allows finer-grained control, and cargo-fmt understands the conventions of a project that uses Cargo. To format any Cargo project:

$ cargo fmt

This reformats all the Rust code in the current crate. It should only change the code style, not the code semantics. More: the rustfmt documentation (github.com/rust-lang/rustfmt).

The Rust Programming Language · Appendix

35

Appendix · D Useful Development Tools

Fix your code with rustfix: a warning

The rustfix tool is included with Rust installations and can automatically fix compiler warnings that have a clear way to correct the problem that’s likely what you want. Consider this code:

src/main.rs

fn main() {

    let mut x = 42;

    println!("{x}");

}

We define x as mutable but never actually mutate it. Rust warns us about that (right).

$ cargo build

   Compiling myprogram v0.1.0 (file:///projects/myprogram)

warning: variable does not need to be mutable

 --> src/main.rs:2:9

  |

2 |     let mut x = 0;

  |         ----^

  |         |

  |         help: remove this `mut`

  |

  = note: `#[warn(unused_mut)]` on by default

The Rust Programming Language · Appendix

36

Appendix · D Useful Development Tools

Fix your code with rustfix: cargo fix

The warning suggests removing the mut keyword. We can apply that suggestion automatically with the rustfix tool by running cargo fix:

Running cargo fix:

$ cargo fix

    Checking myprogram v0.1.0 (file:///projects/myprogram)

      Fixing src/main.rs (1 fix)

    Finished dev [unoptimized + debuginfo] target(s) in 0.59s

src/main.rs afterwards — changed by cargo fix:

fn main() {

    let x = 42;

    println!("{x}");

}

The variable x is now immutable, and the warning no longer appears. You can also use cargo fix to transition your code between different Rust editions (Appendix E).

The Rust Programming Language · Appendix

37

Appendix · D Useful Development Tools

More lints with Clippy

Definition A.12 (Clippy). A collection of lints that analyze your code so you can catch common mistakes and improve your Rust code. Clippy is included with standard Rust installations.

To run Clippy’s lints on any Cargo project, enter:

$ cargo clippy

For example, say you write a program that uses an approximation of a mathematical constant, such as pi:

src/main.rs

fn main() {

    let x = 3.1415;

    let r = 8.0;

    println!("the area of the circle is {}", x * r * r);

}

The Rust Programming Language · Appendix

38

Appendix · D Useful Development Tools

Clippy’s approx_constant error

Running cargo clippy on this project results in this error:

error: approximate value of `f{32, 64}::consts::PI` found

 --> src/main.rs:2:13

  |

2 |     let x = 3.1415;

  |             ^^^^^^

  |

  = note: `#[deny(clippy::approx_constant)]` on by default

  = help: consider using the constant directly

  = help: for further information visit

        https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant

This error lets you know that Rust already has a more precise PI constant defined, and that your program would be more correct if you used the constant instead. You would then change your code to use the PI constant.

The Rust Programming Language · Appendix

39

Appendix · D Useful Development Tools

Clippy: the fixed program

The following code doesn’t result in any errors or warnings from Clippy:

src/main.rs

fn main() {

    let x = std::f64::consts::PI;

    let r = 8.0;

    println!("the area of the circle is {}", x * r * r);

}

Remark. For more information on Clippy, see its documentation (github.com/rust-lang/rust-clippy).

The Rust Programming Language · Appendix

40

Appendix · D Useful Development Tools

IDE integration using rust-analyzer

To help with IDE integration, the Rust community recommends using rust-analyzer (rust-analyzer.github.io). This tool is a set of compiler-centric utilities that speak the Language Server Protocol.

Definition A.13 (Language Server Protocol). A specification for IDEs and programming languages to communicate with each other (langserver.org).

Different clients can use rust-analyzer, such as the Rust analyzer plug-in for Visual Studio Code.

  1. Visit the rust-analyzer project’s home page (rust-analyzer.github.io) for installation instructions.
  2. Install the language server support in your particular IDE.

Your IDE then gains capabilities such as autocompletion, jump to definition, and inline errors.

The Rust Programming Language · Appendix

41

Appendix · E Editions

Why Rust has editions

In Chapter 1, cargo new added a bit of metadata about an edition to your Cargo.toml file. This appendix explains what that means.

The Rust language and compiler have a six-week release cycle, so users get a constant stream of new features. Other programming languages release larger changes less often; Rust releases smaller updates more frequently. After a while, all of these tiny changes add up — but from release to release, it can be difficult to look back and say, “Wow, between Rust 1.10 and Rust 1.31, Rust has changed a lot!”

Definition A.14 (Edition). A package, produced by the Rust team every three years or so, that brings together the features that have landed into a clear package with fully updated documentation and tooling. New editions ship as part of the usual six-week release process.

The Rust Programming Language · Appendix

42

Appendix · E Editions

Choosing an edition

Editions serve different purposes for different people:

  • For active Rust users, a new edition brings together incremental changes into an easy-to-understand package.
  • For non-users, it signals that some major advancements have landed, which might make Rust worth another look.
  • For those developing Rust, it provides a rallying point for the project as a whole.

At the time of this writing, four Rust editions are available: Rust 2015, Rust 2018, Rust 2021, and Rust 2024. The book is written using Rust 2024 edition idioms.

The edition key in Cargo.toml indicates which edition the compiler should use for your code. If the key doesn’t exist, Rust uses 2015 as the edition value, for backward compatibility reasons.

Each project can opt in to an edition other than the default 2015 edition. Editions can contain incompatible changes, such as a new keyword that conflicts with identifiers in code. However, unless you opt in to those changes, your code will continue to compile even as you upgrade the Rust compiler version you use.

The Rust Programming Language · Appendix

43

Appendix · E Editions

Editions interoperate

All Rust compiler versions support any edition that existed prior to that compiler’s release, and they can link crates of any supported editions together. Edition changes only affect the way the compiler initially parses code.

Example A.15. If you’re using Rust 2015 and one of your dependencies uses Rust 2018, your project will compile and be able to use that dependency. The opposite situation — your project uses Rust 2018 and a dependency uses Rust 2015 — works as well.

To be clear: most features will be available on all editions, and developers using any Rust edition will continue to see improvements as new stable releases are made. However, in some cases, mainly when new keywords are added, some new features might only be available in later editions. You will need to switch editions if you want to take advantage of such features.

Remark. For more details, see The Rust Edition Guide (doc.rust-lang.org/stable/edition-guide), a complete book that enumerates the differences between editions and explains how to automatically upgrade your code to a new edition via cargo fix.

The Rust Programming Language · Appendix

44

Appendix · F Translations

Translations of the book (1 of 3)

Resources in languages other than English. Most are still in progress; see the Translations label on the book’s GitHub issues to help, or to let the maintainers know about a new translation.

Table A.13: Translations (repositories on github.com unless a full host is given)

LanguageRepository
Portuguese (Brazil)rust-br/rust-book-pt-br
Portuguese (Portugal)nunojesus/rust-book-pt-pt
Simplified ChineseKaiserY/trpl-zh-cn; gnu4cn/rust-lang-Zh_CN
Traditional Chineserust-tw/book-tw
Ukrainianrust-lang-ua.github.io/rustbook_ukrainian
Spanishthecodix/book; alternate: ManRR/rust-book-es; RustLangES/rust-book-es
Russianrust-lang-ru/book
Koreanrust-kr/doc.rust-kr.org

The Rust Programming Language · Appendix

45

Appendix · F Translations

Translations of the book (2 of 3)

Table A.13 (continued): Translations (repositories on github.com unless a full host is given)

LanguageRepository
Japaneserust-lang-ja/book-ja
FrenchJimskapt/rust-book-fr
Polishpaytchoo/book-pl
Cebuanoagentzero1/book
Tagalogjosephace135/book
Esperantopsychoslave/Rust-libro
GreekTChatzigiannakis/rust-book-greek
Swedishsebras/book
Farsi; Persian (FA)RustFarsi/book; persian-rust/book

The Rust Programming Language · Appendix

46

Appendix · F Translations

Translations of the book (3 of 3)

Table A.13 (continued): Translations (repositories on github.com unless a full host is given)

LanguageRepository
Germanrust-lang-de/rustbook-de
Hindivenkatarun95/rust-book-hindi
Thairust-lang-th/book-th
DanishDanKHansen/book-dk
Uzbekrust-lang-uz/book
Vietnamesetuanemdev/rust-book-vn
Italiannixxo.github.io/rust-lang-book-it
BengaliIsmailHosenIsmailJames/rust-book-bn

Remark. The book lists each language under its own name (for example Deutsch, Español, Français); this deck gives English names. The list is open: new translations are announced through the Translations label on github.com/rust-lang/book issues.

The Rust Programming Language · Appendix

47

Appendix · G How Rust is Made and Nightly Rust

Stability without stagnation

This appendix is about how Rust is made and how that affects you as a Rust developer.

As a language, Rust cares a lot about the stability of your code. Rust should be a rock-solid foundation you can build on, and if things were constantly changing, that would be impossible.

At the same time, if the Rust team can’t experiment with new features, they may not find out important flaws until after their release, when things can no longer be changed.

Definition A.16 (Stability without stagnation). Rust’s solution to this tension. Its guiding principle: you should never have to fear upgrading to a new version of stable Rust. Each upgrade should be painless, but should also bring you new features, fewer bugs, and faster compile times.

The Rust Programming Language · Appendix

48

Appendix · G How Rust is Made and Nightly Rust

Choo, choo! Release channels and riding the trains

Rust development operates on a train schedule: all development is done in the main branch of the Rust repository, and releases follow a software release train model, which has been used by Cisco IOS and other software projects.

Definition A.17 (Release channel). One of the three streams in which Rust is released: Nightly, Beta, and Stable. Most Rust developers primarily use the stable channel, but those who want to try out experimental new features may use nightly or beta.

An example of how development and release work: assume the Rust team is working on the release of Rust 1.5. (That release happened in December 2015, but it gives realistic version numbers.) A new feature is added to Rust: a new commit lands on the main branch. Each night, a new nightly version of Rust is produced. Every day is a release day, and these releases are created automatically by the release infrastructure. So as time passes, the releases look like this, once a night:

nightly: * - - * - - *

The Rust Programming Language · Appendix

49

Appendix · G How Rust is Made and Nightly Rust

The trains: beta branches off, regressions get fixed

1. Every six weeks, it’s time to prepare a new release! The beta branch of the Rust repository branches off from the main branch used by nightly. Now there are two releases:

nightly: * - - * - - *

                     |

beta:                *

2. Most Rust users do not use beta releases actively, but test against beta in their CI system to help Rust discover possible regressions. Meanwhile, there’s still a nightly release every night:

nightly: * - - * - - * - - * - - *

                     |

beta:                *

3. Say a regression is found. Good thing there was time to test the beta release before the regression snuck into a stable release! The fix is applied to the main branch, so nightly is fixed; then the fix is backported to the beta branch, and a new beta release is produced:

nightly: * - - * - - * - - * - - * - - *

                     |

beta:                * - - - - - - - - *

The Rust Programming Language · Appendix

50

Appendix · G How Rust is Made and Nightly Rust

The trains: stable ships, the next beta departs

4. Six weeks after the first beta was created, it’s time for a stable release! The stable branch is produced from the beta branch:

nightly: * - - * - - * - - * - - * - - * - * - *

                     |

beta:                * - - - - - - - - *

                                       |

stable:                                *

5. Hooray! Rust 1.5 is done! But because the six weeks have gone by, a new beta of the next version of Rust, 1.6, is needed too. So after stable branches off of beta, the next version of beta branches off of nightly again:

nightly: * - - * - - * - - * - - * - - * - * - *

                     |                         |

beta:                * - - - - - - - - *       *

                                       |

stable:                                *

The Rust Programming Language · Appendix

51

Appendix · G How Rust is Made and Nightly Rust

Why the train model works

Definition A.18 (Train model). The release model in which every six weeks a release “leaves the station”, but still has to take a journey through the beta channel before it arrives as a stable release.

Rust releases every six weeks, like clockwork. If you know the date of one Rust release, you can know the date of the next one: it’s six weeks later. A nice aspect of releases scheduled every six weeks is that the next train is coming soon. If a feature happens to miss a particular release, there’s no need to worry: another one is happening in a short time! This helps reduce pressure to sneak possibly unpolished features in close to the release deadline.

Thanks to this process, you can always check out the next build of Rust and verify for yourself that it’s easy to upgrade to: if a beta release doesn’t work as expected, you can report it to the team and get it fixed before the next stable release happens! Breakage in a beta release is relatively rare, but rustc is still a piece of software, and bugs do exist.

The Rust Programming Language · Appendix

52

Appendix · G How Rust is Made and Nightly Rust

Maintenance time and unstable features

Maintenance time

The Rust project supports the most recent stable version. When a new stable version is released, the old version reaches its end of life (EOL). This means each version is supported for six weeks.

Unstable features

There’s one more catch with this release model: unstable features. Rust uses a technique called “feature flags” to determine what features are enabled in a given release.

Definition A.19 (Feature flag). A flag behind which a feature under active development lands on the main branch — and therefore in nightly. To try out the work-in-progress feature, you must be using a nightly release of Rust and annotate your source code with the appropriate flag to opt in.

The Rust Programming Language · Appendix

53

Appendix · G How Rust is Made and Nightly Rust

Unstable features stay on nightly

If you’re using a beta or stable release of Rust, you can’t use any feature flags. This is the key that allows practical use of new features before they are declared stable forever. Those who wish to opt into the bleeding edge can do so, and those who want a rock-solid experience can stick with stable and know that their code won’t break. Stability without stagnation.

Example A.20. Opting in to an unstable feature is a crate-level attribute naming the flag; it compiles only on a nightly toolchain, and beta or stable reject it.

#![feature(never_type)]  // at the top of src/main.rs or src/lib.rs

The book only contains information about stable features, as in-progress features are still changing, and surely they’ll be different between when the book was written and when they get enabled in stable builds. You can find documentation for nightly-only features online.

The Rust Programming Language · Appendix

54

Appendix · G How Rust is Made and Nightly Rust

Rustup and the role of Rust nightly

Rustup makes it easy to change between different release channels of Rust, on a global or per-project basis. By default, you’ll have stable Rust installed. To install nightly, for example:

$ rustup toolchain install nightly

Definition A.21 (Toolchain). A release of Rust together with its associated components, as installed and managed by rustup.

You can see all of the toolchains you have installed with rustup as well. Here’s an example on one of the authors’ Windows computers:

> rustup toolchain list

stable-x86_64-pc-windows-msvc (default)

beta-x86_64-pc-windows-msvc

nightly-x86_64-pc-windows-msvc

The Rust Programming Language · Appendix

55

Appendix · G How Rust is Made and Nightly Rust

Using nightly for one project: rustup override

As the list shows, the stable toolchain is the default. Most Rust users use stable most of the time. You might want to use stable most of the time but use nightly on a specific project, because you care about a cutting-edge feature.

To do so, use rustup override in that project’s directory to set the nightly toolchain as the one rustup should use when you’re in that directory:

$ cd ~/projects/needs-nightly

$ rustup override set nightly

Now, every time you call rustc or cargo inside ~/projects/needs-nightly, rustup makes sure that you are using nightly Rust rather than your default of stable Rust. This comes in handy when you have a lot of Rust projects!

The Rust Programming Language · Appendix

56

Appendix · G How Rust is Made and Nightly Rust

The RFC process and teams

So how do you learn about these new features? Rust’s development model follows a Request For Comments (RFC) process.

Definition A.22 (RFC). A written proposal for an improvement in Rust. Anyone can write RFCs to improve Rust.

The proposals are reviewed and discussed by the Rust team, which is comprised of many topic subteams. There’s a full list of the teams on Rust’s website (rust-lang.org/governance), including teams for each area of the project: language design, compiler implementation, infrastructure, documentation, and more.

The appropriate team reads the proposal and the comments, writes some comments of their own, and eventually there’s consensus to accept or reject the feature.

The Rust Programming Language · Appendix

57

Appendix · G How Rust is Made and Nightly Rust

From accepted RFC to stable feature

Once a team reaches consensus to accept a feature, it travels the rest of the way like this:

  1. An issue is opened on the Rust repository, and someone can implement it. The person who implements it very well may not be the person who proposed the feature in the first place!
  2. When the implementation is ready, it lands on the main branch behind a feature gate, as discussed in “Unstable features”.
  3. After some time, once Rust developers who use nightly releases have been able to try out the new feature, team members discuss the feature and how it’s worked out on nightly, and decide whether it should make it into stable Rust.
  4. If the decision is to move forward, the feature gate is removed, and the feature is now considered stable! It rides the trains into a new stable release of Rust.

The Rust Programming Language · Appendix

58

Appendix · Summary

Appendix summary

The appendices are reference material to come back to:

  • A — keywords in use and reserved; r# raw identifiers let you use any keyword as a name.
  • B — every operator (with its overloading trait) and every non-operator symbol.
  • C — the derivable traits: Debug, PartialEq/Eq, PartialOrd/Ord, Clone/Copy, Hash, Default.
  • D — cargo fmt, cargo fix, cargo clippy, and rust-analyzer for IDEs.
  • E — editions (2015, 2018, 2021, 2024) are opt-in via Cargo.toml and interoperate freely.
  • F — community translations of the book in many languages.
  • G — nightly, beta and stable ride six-week trains; unstable features stay behind feature flags on nightly; RFCs drive new features.

Remark. This is the end of the book. From here, keep the standard library documentation (rustup doc) and The Rust Edition Guide close at hand, and follow new features as they ride the trains to stable.

The Rust Programming Language · Appendix

59