Rust Language Cheat Sheet 25.09.2020

Contains clickable links to The Book BK, Rust by Example EX, Std Docs STD, Nomicon NOM, Reference REF. Other symbols used: largely deprecated 🗑️, has a minimum edition '18, is work in progress 🚧, or bad 🛑.

Data Structuresurl

Data types and memory locations defined via keywords.

Example Explanation struct S {} Define a struct BK EX STD REF with named fields. struct S { x: T } Define struct with named field x of type T . struct S ​ (T); Define "tupled" struct with numbered field .0 of type T . struct S; Define zero sized NOM unit struct. Occupies no space, optimized away. enum E {} Define an enum BK EX REF , c. algebraic data types, tagged unions. enum E { A, B ​ (), C {} } Define variants of enum; can be unit- A , tuple- B ​ () and struct-like C{} . enum E { A = 1 } If variants are only unit-like, allow discriminant values, e.g., for FFI. union U {} Unsafe C-like union REF for FFI compatibility. static X: T = T(); Global variable BK EX REF with 'static lifetime, single memory location. const X: T = T(); Defines constant BK EX REF. Copied into a temporary when used. let x: T; Allocate T bytes on stack1 bound as x . Assignable once, not mutable. let mut x: T; Like let , but allow for mutability BK EX and mutable borrow.2 x = y; Moves y to x , invalidating y if T is not Copy , STD and copying y otherwise.

1 Bound variables BK EX REF live on stack for synchronous code. In async {} code they become part async's state machine, may reside on heap.

2 Technically mutable and immutable are misnomer. Immutable binding or shared reference may still contain Cell STD, giving interior mutability.

Creating and accessing data structures; and some more sigilic types.

Example Explanation S { x: y } Create struct S {} or use 'ed enum E::S {} with field x set to y . S { x } Same, but use local variable x for field x . S { ..s } Fill remaining fields from s , esp. useful with Default. S { 0: x } Like S ​ (x) below, but set field .0 with struct syntax. S ​ (x) Create struct S ​ (T) or use 'ed enum E::S ​ () with field .0 set to x . S If S is unit struct S; or use 'ed enum E::S create value of S . E::C { x: y } Create enum variant C . Other methods above also work. () Empty tuple, both literal and type, aka unit. STD (x) Parenthesized expression. (x,) Single-element tuple expression. EX STD REF (S,) Single-element tuple type. [S] Array type of unspecified length, i.e., slice. EX STD REF Can't live on stack. * [S; n] Array type EX STD of fixed length n holding elements of type S . [x; n] Array instance with n copies of x . REF [x, y] Array instance with given elements x and y . x[0] Collection indexing. Overloadable Index, IndexMut x[..] Collection slice-like indexing via RangeFull, c. slices. x[a..] Collection slice-like indexing via RangeFrom. x[..b] Collection slice-like indexing RangeTo. x[a..b] Collection slice-like indexing via Range. a..b Right-exclusive range REF creation, also seen as ..b . a..=b Inclusive range creation, also seen as ..=b . s.x Named field access, REF might try to Deref if x not part of type S . s.0 Numbered field access, used for tuple types S ​ (T) .

* For now,RFC pending completion of tracking issue.

References & Pointersurl

Granting access to un-owned memory. Also see section on Generics & Constraints.

Example Explanation &S Shared reference BK STD NOM REF (space for holding any &s ). &[S] Special slice reference that contains ( address , length ). &str Special string reference that contains ( address , length ). &mut S Exclusive reference to allow mutability (also &mut [S] , &mut dyn S , ...) &dyn T Special trait object BK reference that contains ( address , vtable ). *const S Immutable raw pointer type BK STD REF w/o memory safety. *mut S Mutable raw pointer type w/o memory safety. &s Shared borrow BK EX STD (e.g., address, len, vtable, ... of this s , like 0x1234 ). &mut s Exclusive borrow that allows mutability. EX ref s Bind by reference. EX 🗑️ let ref r = s; Equivalent to let r = &s . let S { ref mut x } = s; Mutable ref binding ( let x = &mut s.x ), shorthand destructuring ↓ version. *r Dereference BK STD NOM a reference r to access what it points to. *r = s; If r is a mutable reference, move or copy s to target memory. s = *r; Make s a copy of whatever r references, if that is Copy . s = *my_box; Special case for Box that can also move out Box'ed content if it isn't Copy . 'a A lifetime parameter, BK EX NOM REF, duration of a flow in static analysis. &'a S Only accepts a s with an address that lives 'a or longer. &'a mut S Same, but allow content of address to be changed. struct S<'a> {} Signals S will contain address with lifetime 'a . Creator of S decides 'a . trait T<'a> {} Signals a S which impl T for S might contain address. fn f<'a>(t: &'a T) Same, for function. Caller decides 'a . 'static Special lifetime lasting the entire program execution.

Functions & Behaviorurl

Define units of code and their abstractions.

Example Explanation trait T {} Define a trait; BK EX REF common behavior others can implement. trait T : R {} T is subtrait of supertrait REF R . Any S must impl R before it can impl T . impl S {} Implementation REF of functionality for a type S , e.g., methods. impl T for S {} Implement trait T for type S . impl !T for S {} Disable an automatically derived auto trait NOM REF. fn f() {} Definition of a function; BK EX REF or associated function if inside impl . fn f() -> S {} Same, returning a value of type S. fn f(&self) {} Define a method, BK EX e.g., within an impl S {} . const fn f() {} Constant fn usable at compile time, e.g., const X: u32 = f(Y) . '18 async fn f() {} Async REF '18 function transformation, makes f return an impl Future . STD async fn f() -> S {} Same, but make f return an impl Future<Output=S> . async { x } Used within a function, make { x } an impl Future<Output=X> . fn() -> S Function pointers, BK STD REF, memory holding address of a callable. Fn() -> S Callable Trait, BK STD (also FnMut , FnOnce ), implemented by closures, fn's ... || {} A closure BK EX REF that borrows its captures. REF |x| {} Closure with a bound parameter x . |x| x + x Closure without block expression; may only consist of single expression. move |x| x + y Closure taking ownership of its captures. return || true Closures sometimes look like logical ORs (here: return a closure). unsafe If you enjoy debugging segfaults Friday night; unsafe code. ↓ BK EX NOM REF unsafe f() {} Sort-of means "can cause UB, ↓ YOU must check requirements". unsafe {} Guarantees to compiler "I have checked requirements, trust me".

Control Flowurl

Control execution within a function.

Example Explanation while x {} Loop REF, run while expression x is true. loop {} Loop infinitely REF until break . Can yield value with break x . for x in iter {} Syntactic sugar to loop over iterators. BK STD REF if x {} else {} Conditional branch REF if expression is true. 'label: loop {} Loop label EX REF, useful for flow control in nested loops. break Break expression REF to exit a loop. break x Same, but make x value of the loop expression (only in actual loop ). break 'label Exit not only this loop, but the enclosing one marked with 'label . continue Continue expression REF to the next loop iteration of this loop. continue 'label Same, but instead of enclosing loop marked with 'label . x? If x is Err or None, return and propagate. BK EX STD REF x.await Only works inside async . Yield flow until Future STD or Stream x ready. REF '18 return x Early return from function. More idiomatic way is to end with expression. f() Invoke callable f (e.g., a function, closure, function pointer, Fn , ...). x.f() Call member function, requires f takes self , &self , ... as first argument. X::f(x) Same as x.f() . Unless impl Copy for X {} , f can only be called once. X::f(&x) Same as x.f() . X::f(&mut x) Same as x.f() . S::f(&x) Same as x.f() if X derefs to S , i.e., x.f() finds methods of S . T::f(&x) Same as x.f() if X impl T , i.e., x.f() finds methods of T if in scope. X::f() Call associated function, e.g., X::new() . <X as T>::f() Call trait method T::f() implemented for X .

Organizing Codeurl

Segment projects into smaller units and minimize dependencies.

Example Explanation mod m {} Define a module, BK EX REF get definition from inside {} . ↓ mod m; Define a module, get definition from m.rs or m/mod.rs . ↓ a::b Namespace path EX REF to element b within a ( mod , enum , ...). ::b Search b relative to crate root. 🗑️ crate::b Search b relative to crate root. '18 self::b Search b relative to current module. super::b Search b relative to parent module. use a::b; Use EX REF b directly in this scope without requiring a anymore. use a::{b, c}; Same, but bring b and c into scope. use a::b as x; Bring b into scope but name x , like use std::error::Error as E . use a::b as _; Bring b anonymously into scope, useful for traits with conflicting names. use a::*; Bring everything from a into scope. pub use a::b; Bring a::b into scope and reexport from here. pub T "Public if parent path is public" visibility BK for T . pub(crate) T Visible at most in current crate. pub(self) T Visible at most in current module. pub(super) T Visible at most in parent. pub(in a::b) T Visible at most in a::b . extern crate a; Declare dependency on external crate BK EX REF 🗑️ ; just use a::b in '18. extern "C" {} Declare external dependencies and ABI (e.g., "C" ) from FFI. BK EX NOM REF extern "C" fn f() {} Define function to be exported with ABI (e.g., "C" ) to FFI.

Type Aliases and Castsurl

Short-hand names of types, and methods to convert one type to another.

Example Explanation type T = S; Create a type alias BK REF, i.e., another name for S . Self Type alias for implementing type REF, e.g. fn new() -> Self . self Method subject in fn f(self) {} , same as fn f(self: Self) {} . &self Same, but refers to self as borrowed, same as f(self: &Self) &mut self Same, but mutably borrowed, same as f(self: &mut Self) self: Box<Self> Arbitrary self type, add methods to smart pointers ( my_box.f_of_self() ). S as T Disambiguate BK REF type S as trait T , e.g., <S as T>::f() . S as R In use of symbol, import S as R , e.g., use a::S as R . x as u32 Primitive cast EX REF, may truncate and be a bit surprising. NOM

Macros & Attributesurl

Code generation constructs expanded before the actual compilation happens.

Example Explanation m!() Macro BK STD REF invocation, also m!{} , m![] (depending on macro). #[attr] Outer attribute. EX REF, annotating the following item. #![attr] Inner attribute, annotating the surrounding item.

Inside a declarative BK macro by example BK EX REF macro_rules! implementation these work: Within Macros Explanation $x:ty Macro capture, with the ty part being: $x:item An item, like a function, struct, module, etc. $x:block A block {} of statements or expressions, e.g., { let x = 5; } $x:stmt A statement, e.g., let x = 1 + 1; , String::new(); or vec![]; $x:expr An expression, e.g., x , 1 + 1 , String::new() or vec![] $x:pat A pattern, e.g., Some(t) , (17, 'a') or _ . $x:ty A type, e.g., String , usize or Vec<u8> . $x:ident An identifier, for example in let x = 0; the identifier is x . $x:path A path (e.g. foo , ::std::mem::replace , transmute::<_, int> , …). $x:literal A literal (e.g. 3 , "foo" , b"bar" , etc.). $x:lifetime A lifetime (e.g. 'a , 'static , etc.). $x:meta A meta item; the things that go inside #[...] and #![...] attributes. $x:vis A visibility modifier; pub , pub(crate) , etc. $x:tt A single token tree, see here for more details. $x Macro substitution, e.g., use the captured $x:ty from above. $(x),* Macro repetition "zero or more times" in macros by example. $(x),? Same, but "zero or one time". $(x),+ Same, but "one or more times". $(x)<<+ In fact separators other than , are also accepted. Here: << . $crate Special hygiene variable, crate where macros is defined. ?

Pattern Matchingurl

Constructs found in match or let expressions, or function parameters.

Example Explanation match m {} Initiate pattern matching BK EX REF, then use match arms, c. next table. let S(x) = get(); Notably, let also destructures EX similar to the table below. let S { x } = s; Only x will be bound to value s.x . let (_, b, _) = abc; Only b will be bound to value abc.1 . let (a, ..) = abc; Ignoring 'the rest' also works. let (.., a, b) = (1, 2); Specific bindings take precedence over 'the rest', here a is 1 , b is 2 . let Some(x) = get(); Won't work 🛑 if pattern can be refuted REF, use if let instead. if let Some(x) = get() {} Branch if pattern can be assigned (e.g., enum variant), syntactic sugar. * fn f(S { x }: S) Function parameters also work like let , here x bound to s.x of f(s) .

* Desugars to match get() { Some(x) => {}, _ => () } .

Pattern matching arms in match expressions. Left side of these arms can also be found in let expressions.

Match Arm Explanation E::A => {} Match enum variant A , c. pattern matching. BK EX REF E::B ( .. ) => {} Match enum tuple variant B , wildcard any index. E::C { .. } => {} Match enum struct variant C , wildcard any field. S { x: 0, y: 1 } => {} Match struct with specific values (only accepts s with s.x of 0 and s.y of 1 ). S { x: a, y: b } => {} Match struct with any(!) values and bind s.x to a and s.y to b . S { x, y } => {} Same, but shorthand with s.x and s.y bound as x and y respectively. S { .. } => {} Match struct with any values. D => {} Match enum variant E::D if D in use . D => {} Match anything, bind D ; possibly false friend 🛑 of E::D if D not in use . _ => {} Proper wildcard that matches anything / "all the rest". (a, 0) => {} Match tuple with any value for a and 0 for second. [a, 0] => {} Slice pattern, REF 🔗 match array with any value for a and 0 for second. [1, ..] => {} Match array starting with 1 , any value for rest; subslice pattern. ? [2, .., 5] => {} Match array starting with 1 , ending with 5 . [2, x @ .., 5] => {} Same, but also bind x to slice representing middle (c. next entry). x @ 1..=5 => {} Bind matched to x ; pattern binding, BK EX REF here x would be 1 , 2 , ... or 5 . 0 | 1 => {} Pattern alternatives (or-patterns). E::A | E::Z Same, but on enum variants. E::C {x} | E::D {x} Same, but bind x if all variants have it. S { x } if x > 10 => {} Pattern match guards, BK EX REF condition must be true as well to match.

Generics & Constraintsurl

Generics combine with many other constructs such as struct S<T> , fn f<T>() , ...

Example Explanation S<T> A generic BK EX type with a type parameter ( T is placeholder name here). S<T: R> Type short hand trait bound BK EX specification ( R must be actual trait). T: R, P: S Independent trait bounds (here one for T and one for P ). T: R, S Compile error, 🛑 you probably want compound bound R + S below. T: R + S Compound trait bound BK EX, T must fulfill R and S . T: R + 'a Same, but w. lifetime. T must fulfill R , if T has lifetimes, must outlive 'a . T: ?Sized Opt out of a pre-defined trait bound, here Sized . ? T: 'a Type lifetime bound EX; if T has references, they must outlive 'a . T: 'static Same; does esp. not mean value t will 🛑 live 'static , only that it could. 'b: 'a Lifetime 'b must live at least as long as (i.e., outlive) 'a bound. S<T> where T: R Same as S<T: R> but more pleasant to read for longer bounds. S<T = R> Default type parameter BK for associated type. S<'_> Inferred anonymous lifetime; asks compiler to 'figure it out' if obvious. S<_> Inferred anonymous type, e.g., as let x: Vec<_> = iter.collect() S::<T> Turbofish STD call site type disambiguation, e.g. f::<u32>() . trait T<X> {} A trait generic over X . Can have multiple impl T for S (one per X ). trait T { type X; } Defines associated type BK REF X . Only one impl T for S possible. type X = R; Set associated type within impl T for S { type X = R; } . impl<T> S<T> {} Implement functionality for any T in S<T> . impl S<T> {} Implement functionality for exactly S<T> (e.g., S<u32> ). fn f() -> impl T Existential types BK, returns an unknown-to-caller S that impl T . fn f(x: &impl T) Trait bound,"impl traits" BK, somewhat similar to fn f<S:T>(x: &S) . fn f(x: &dyn T) Marker for dynamic dispatch BK REF, f will not be monomorphized. fn f() where Self: R; In trait T {} , make f accessible only on types known to also impl R . fn f() where Self: R {} Esp. useful w. default methods (non dflt. would need be impl'ed anyway). for<'a> Higher-ranked trait bounds. NOM REF trait T: for<'a> R<'a> {} Any S that impl T would also have to fulfill R for any lifetime.

Strings & Charsurl

Rust has several ways to create textual values.

Example Explanation "..." String literal, REF UTF-8, will interpret

as line break 0xA , ... r"..." Raw string literal. REF UTF-8, won't interpret

, ... r#"..."# Raw string literal, UTF-8, but can also contain " . Number of # can vary. b"..." Byte string literal; REF constructs ASCII [u8] , not a string. br"..." , br#"..."# Raw byte string literal, ASCII [u8] , combination of the above. '🦀' Character literal, REF fixed 4 byte unicode 'char'. STD b'x' ASCII byte literal. REF

No comment.

Example Explanation // Line comment, use these to document code flow or internals. /// Outer line doc comment, BK EX REF use these on types. //! Inner line doc comment, mostly used at start of file to document module. /*...*/ Block comment. /**...*/ Outer block doc comment. /*!...*/ Inner block doc comment. ```rust ... ``` In doc comments, include a doc test (doc code running on cargo test ). # In doc tests, hide line from documentation ( ``` # use x::hidden; ``` ).

Miscellaneousurl

These sigils did not fit any other category but are good to know nonetheless.

Example Explanation ! Always empty never type. 🚧 BK EX STD REF _ Unnamed variable binding, e.g., |x, _| {} . let _ = x; Unnamed assignment is no-op, does not 🛑 move out x or preserve scope! _x Variable binding explicitly marked as unused. 1_234_567 Numeric separator for visual clarity. 1_u8 Type specifier for numeric literals EX REF (also i8 , u16 , ...). 0xBEEF , 0o777 , 0b1001 Hexadecimal ( 0x ), octal ( 0o ) and binary ( 0b ) integer literals. r#foo A raw identifier BK EX for edition compatibility. x; Statement REF terminator, c. expressions EX REF

Common Operatorsurl

Rust supports most operators you would expect ( + , * , % , = , == ...), including overloading. STD Since they behave no differently in Rust we do not list them here.

Behind the Scenesurl Memory & Lifetimesurl Why moves, references and lifetimes are how they are. 🔥 This section is brand new, feedback very welcome! 🔥 Types & Moves Application Memory S(1) Application Memory Application memory in itself is just array of bytes.

It is segmented, amongst others, into: stack (small, low-overhead memory, 1 most variables go here), heap (large, flexible memory, but always handled via stack proxy like Box<T> ), static (most commonly used as resting place for str part of &str ), code (where bitcode of your functions reside).

Programming languages such as Rust give developers tools to: define what data goes into what segment, express a desire for bitcode with specific properties to be produced, protect themselves from errors while performing these operations.

Most tricky part is tied to how stack evolves, which is our focus. 1 While for each part of the heap someone (the allocator) needs to perform bookkeeping at runtime, the stack is trivially managable: take a few bytes more while you need them, they will be discarded once you leave. The (for performance reasons desired) simplicity of this appraoch, along with the fact that you can tell others about such transient locations (which in turn might want to access them long after you left), form the very essence of why lifetimes exist; and are the subject of the rest of this chapter. Variables S(1) S(1) a t Variables let t = S(1); Reserves memory location with name t of type S and the value S(1) stored inside.

of type and the value stored inside. If declared with let that location lives on stack. 1

that location lives on stack. Note that the term variable has some linguistic ambiguity , 2 it can mean: the name of the location ("rename that variable"), the location itself, 0x7 ("tell me the address of that variable"), the value contained within, S(1) ("increment that variable").

has some , it can mean: Specifically towards the compiler t can mean location of t , here 0x7 , and value within t , here S(1) . 1 Compare above,↑ true for fully synchronous code, but async stack frame might placed it on heap via runtime. 2 It is the author's opinion that this ambiguity related to variables (and lifetimes and scope later) are some of the biggest contributors to the confusion around learning the basics of lifetimes. Whenever you hear one of these terms ask yourself "what exactly is meant here?" Move Semantics S(1) a t Moves let a = t; This will move value within t to location of a , or copy it, if S is Copy .

value within to location of , or copy it, if is . After move location t is invalid and cannot be read anymore. Technically the bits at that location are not really empty, but undefined. If you still had access to t (via unsafe ) they might still look like valid S , but any attempt to use them as valid S is undefined behavior. ↓

is and cannot be read anymore. We do not cover Copy types explicitly here. They change the rules a bit, but not much: They won't be dropped They never leave behind an 'empty' variable location.

types explicitly here. They change the rules a bit, but not much: Type Safety S(1) M { ... } ⛔ a c Type Safety let c: S = M::new(); The type of a variable serves multiple important purposes, it: dictates how the underlying bits are to be interpreted, allows only well-defined operations on these bits prevents random other values or bits from being written to that location.

serves multiple important purposes, it: Here assignment fails to compile since the bytes of M::new() cannot be converted to form of type S .

cannot be converted to form of type . Conversions between types will always fail in general, unless explicit rule allows it (coercion, cast, ...). As an excercise to the reader, any time you see a value of type A being assignable to a location of some type not-exactly-A you should ask yourself: through what mechanism is this possible? Scope & Drop S(1) ▼ C(2) S(2) ▼ S(3) a t c Scope & Drop { let mut c = S(2); c = S(3); // <- Drop called on `c` before assignment. let t = S(1); let a = t; } // <- Scope of `a`, `t`, `c` ends here, drop called on `a`, `c`. Once the 'name' of a non-vacated variable goes out of (drop-) scope , the contained value is dropped . Rule of tumb: execution reaches point where name of variable leaves {} -block it was defined in In detail more tricky, esp. temporaries, ...

, the contained value is . Drop also invoked when new value assigned to existing variable location.

In that case Drop::drop() is called on the location of that value. In the example above drop() is called on a , twice on c , but not on t .

is called on the location of that value. Most non- Copy values get dropped most of the time; exceptions include mem::forget() , Rc cycles, abort() . Call Stack Stack Frame S(1) a x Function Boundaries fn f(x: S) { ... } let a = S(1); // <- We are here f(a); When a function is called , memory for parameters (and return values) are reserved on stack. 1

, memory for parameters (and return values) are reserved on stack. Here before f is invoked value in a is moved to 'agreed upon' location on stack, and during f works like 'local variable' x . 1 Actual location depends on calling convention, might practically not end up on stack at all, but that doesn't change mental model. S(1) a x x Nested Functions fn f(x: S) { if once() { f(x) } // <- We are here (before recursion) } let a = S(1); f(a); Recursively calling functions, or calling other functions, likewise extends the stack frame.

functions, or calling other functions, likewise extends the stack frame. Nesting too many invocations (esp. via unbounded recursion) will cause stack to grow, and eventually to overflow, terminating the app. Validity of Variables S(1) M { } a x m Repurposing Memory fn f(x: S) { if once() { f(x) } let m = M::new() // <- We are here (after recursion) } let a = S(1); f(a); Stack that previously held a certain type will be repurposed across (even within) functions.

Here, recursing on f produced second x , which after recursion was partially reused for m . Key take away so far, there are multiple ways how memory locations that previously held a valid value of a certain type stopped doing so in the meantime. As we will see shortly, this has implications for pointers. References & Pointers Reference Types ▼ S(1) 0x3 a r References as Pointers let a = S(1); let r: &S = &a; A reference type such as &S or &mut S can hold the location of some s .

such as or can hold the some . Here type &S , bound as name r , holds location of variable a ( 0x3 ), that must be type S , obtained via &a .

, bound as name , holds location of variable ( ), that must be type , obtained via . If you think of variable c as specific location, reference r is a switchboard for locations .

as specific location, reference . The type of the reference, like all other types, can often be inferred, so we might omit it from now on: let r: &S = &a; let r = &a; (Mutable) References ▼ S(2) 0x3 S(1) a r d Access to Non-Owned Memory let mut a = S(1); let r = &mut a; let d = r.clone(); // Valid to clone (or copy) from r-target. *r = S(2); // Valid to set new S value to r-target. References can read from ( &S ) and also write to ( &mut S ) location they point to.

( ) and also ( ) location they point to. The dereference *r means to neither use the location of or value within r , but the location r points to .

means to neither use the location of or value within , but the . In example above, clone d is created from *r , and S(2) written to *r . Method Clone::clone(&T) expects a reference itself, which is why we can use r , not *r . On assignment *r = ... old value in location also dropped (not shown above).

is created from , and written to . ▼ S(2) 0x3 M { x } ⛔ ⛔ a r d References Guard Referents let mut a = ...; let r = &mut a; let d = *r; // Invalid to move out value, `a` would be empty. *r = M::new(); // invalid to store non S value, doesn't make sense. While bindings guarantee to always hold valid data, references guarantee to always point to valid data.

Esp. &mut T must provide same guarantees as variables, and some more as they can't dissolve the target: They do not allow writing invalid data. They do not allow moving out data (would leave target empty w/o owner knowing).

must provide same guarantees as variables, and some more as they can't dissolve the target: ▼ C(2) 0x3 c p Raw Pointers let p: *const S = questionable_origin(); In contrast to references, pointers come with almost no guarantees.

They may point to invalid or non-existent data.

Dereferencing them is unsafe , and treating an invalid *p as if it were valid is undefined behavior. ↓ Lifetime Basics C(2) 0x3 "Lifetime" of Things Every entity in a program has some time it is alive.

Loosely speaking, this alive time can be 1 the LOC (lines of code) where an item is available (e.g., a module name). the LOC between when a location is initialized with a value, and when the location is abandoned . the LOC between when a location is first used in a certain way , and when that usage stops . the LOC (or actual time) between when a value is created, and when that value is dropped.

Within the rest of this section, we will refer to the items above as the: scope of that item, irrelevant here. scope of that variable or location. lifetime 2 of that usage. lifetime of that value, might be useful when discussing open file descriptors, but also irrelevant here.

Likewise, lifetime parameters in code, e.g., r: &'a S , are concerned with LOC any location r points to needs to be accessible or locked; unrelated to the 'existence time' (as LOC) of r itself (well, it needs to exist shorter, that's it).

, are &'static S means address must be valid during all lines of code. 1 There is sometimes ambiguity in the docs differentiating the various scopes and lifetimes. We try to be pragmatic here, but suggestions are welcome. 2 Live lines might have been a more appropriate term ... ▼ S(0) S(1) S(2) 0xa a b c r Meaning of r: &'c S Assume you got a r: &'c S from somewhere it means: r holds an address of some S , any address r points to must and will exist for at least 'c , the variable r itself cannot live longer than 'c .

from somewhere it means: ▼ S(0) S(3) S(2) 0x6 ⛔ a b c r Typelikeness of Lifetimes { let b = S(3); { let c = S(2); let r: &'c S = &c; // Does not quite work since we can't name lifetimes of local { // variables in a function body, but very same principle applies let a = S(0); // to functions next page. r = &a; // Location of `a` does not live sufficient many lines -> not ok. r = &b; // Location of `b` lives all lines of `c` and more -> ok. } } } Assume you got a mut r: &mut 'c S from somewhere. That is, a mutable location that can hold a mutable reference.

from somewhere. As mentioned, that reference must guard the targeted memory.

However, the 'c part , like a type, also guards what is allowed into r .

, like a type, also . Here assiging &b ( 0x6 ) to r is valid, but &a ( 0x3 ) would not, as only &b lives equal or longer than &c . ▼ S(0) S(2) 0x6 S(4) ⛔ a b c Borrowed State let mut b = S(0); let r = &mut b; b = S(4); // Will fail since `b` in borrowed state. print_byte(r); Once the address of a variable is taken via &b or &mut b the variable is marked as borrowed .

or the variable is marked as . While borrowed, the content of the addess cannot be modified anymore via original binding b .

. Once address taken via &b or &mut b stops being used (in terms of LOC) original binding b works again. Lifetimes in Functions S(0) S(1) S(2) ? 0x6 0xa a b c r x y Function Parameters fn f(x: &S, y:&S) -> &u8 { ... } let b = S(1); let c = S(2); let r = f(&b, &c); When calling functions that take and return references two interesting things happen: The used local variables are placed in a borrowed state, But it is during compilation unknown which address will be returned.

S(0) S(1) S(2) ? 0x6 0xa a b c r x y Problem of 'Borrowed' Propagation let b = S(1); let c = S(2); let r = f(&b, &c); let a = b; // Are we allowed to do this? let a = c; // Which one is _really_ borrowed? print_byte(r); Since f can return only one address, not in all cases b and c need to stay locked.

can return only one address, not in all cases and need to stay locked. In many cases we can get quality-of-life improvements. Notably, when we know one parameter couldn't have been used in return value anymore.

▼ S(1) S(1) S(2) y + _ 0x6 0xa a b c r x y Lifetimes Propagate Borrowed State fn f<'b, 'c>(x: &'b S, y: &'c S) -> &'c u8 { ... } let b = S(1); let c = S(2); let r = f(&b, &c); // We know returned reference is `c`-based, which must stay locked, // while `b` is free to move. let a = b; print_byte(r); Liftime parameters in signatures, like 'c above, solve that problem.

above, solve that problem. Their primary purpose is: outside the function , to explain based on which input address an output address could be generated, within the function , to guarantee only addresses that live at least 'c are assigned.

The actual lifetimes 'b , 'c are transparently picked by the compiler at call site , based on the borrowed variables the developer gave.

, are transparently picked by the compiler at , based on the borrowed variables the developer gave. They are not equal to the scope (which would be LOC from initialization to destruction) of b or c , but only a minimal subset of their scope called lifetime, that is, a minmal set of LOC based on how long b and c need to be borrowed to perform this call and use the obtained result.

equal to the scope (which would be LOC from initialization to destruction) of or , but only a minimal subset of their scope called lifetime, that is, a minmal set of LOC based on how long and need to be borrowed to perform this call and use the obtained result. In some cases, like if f had 'c: 'b instead, we still couldn't distinguish and both needed to stay locked. S(2) S(1) S(2) y + 1 0x6 0xa a b c r x y Unlocking let mut c = S(2); let r = f(&c); let s = r; // <- Not here, `s` prolongs locking of `c`. print_byte(s); let a = c; // <- But here, no more use of `r` or `s`. A variable location is unlocked again once the last use of any reference that may point to it ends. ↕️ Examples expand by clicking. Language Sugarurl If something works that "shouldn't work now that you think about it", it might be due to one of these. Name Description Coercions NOM 'Weaken' types to match signature, e.g., &mut T to &T . Deref NOM Deref x: T until *x , **x , ... compatible with some target S . Prelude STD Automatic import of basic types. Reborrow Since x: &mut T can't be copied; move new &mut *x instead. Lifetime Elision BK NOM REF Automatically annotate f(x: &T) to f<'a>(x: &'a T) . Method Resolution REF Deref or borrow x until x.f() works. Match Ergonomics RFC Repeatedly dereference scrutinee and add ref and ref mut to bindings. Editorial Comment 💬 — The features above will make your life easier, but might hinder your understanding. If you are new to Rust, you should consider reading about them in more detail.

Data & Typesurl Memory representations of common data types. Basic Typesurl Essential types built into the core of the language. Numeric Types REFurl u8 , i8 u16 , i16 u32 , i32 u64 , i64 u128 , i128 f32 f64 usize , isize Same as ptr on platform.

Unsigned Types Type Max Value u8 255 u16 65_535 u32 4_294_967_295 u64 18_446_744_073_709_551_615 u128 340_282_366_920_938_463_463_374_607_431_768_211_455 usize Depending on platform pointer size, same as u16 , u32 , or u64 . Signed Types Type Max Value i8 127 i16 32_767 i32 2_147_483_647 i64 9_223_372_036_854_775_807 i128 170_141_183_460_469_231_731_687_303_715_884_105_727 isize Depending on platform pointer size, same as i16 , i32 , or i64 . Type Min Value i8 -128 i16 -32_768 i32 -2_147_483_648 i64 -9_223_372_036_854_775_808 i128 -170_141_183_460_469_231_731_687_303_715_884_105_728 isize Depending on platform pointer size, same as i16 , i32 , or i64 . Float Types Sample bit representation* for a f32 : S E E E E E E E E F F F F F F F F F F F F F F F F F F F F F F F Explanation: f32 S (1) E (8) F (23) Value Normalized number ± 1 to 254 any ±(1.F) 2 * 2E-127 Denormalized number ± 0 non-zero ±(0.F) 2 * 2-126 Zero ± 0 0 ±0 Infinity ± 255 0 ±∞ NaN ± 255 non-zero NaN Similarly, for f64 types this would look like: f64 S (1) E (11) F (52) Value Normalized number ± 1 to 2046 any ±(1.F) 2 * 2E-1023 Denormalized number ± 0 non-zero ±(0.F) 2 * 2-1022 Zero ± 0 0 ±0 Infinity ± 2047 0 ±∞ NaN ± 2047 non-zero NaN * Float types follow IEEE 754-2008 and depend on platform endianness. Textual Types REFurl char Any UTF-8 scalar. str ... U T F - 8 ... unspecified times Rarely seen alone, but as &str instead. Basics Type Description char Always 4 bytes and only holds a single Unicode scalar value 🔗. str An u8 -array of unknown length guaranteed to hold UTF-8 encoded code points. Usage Chars Description let c = 'a'; Often a char (unicode scalar) can coincide with your intuition of character. let c = '❤'; It can also hold many Unicode symbols. let c = '❤️'; But not always. Given emoji is two char (see Encoding) and can't 🛑 be held by c .1 c = 0xffff_ffff; Also, chars are not allowed 🛑 to hold arbitrary bit patterns. 1 Fun fact, due to the Zero-width joiner (⨝) what the user perceives as a character can get even more unpredictable: 👨‍👩‍👧 is in fact 5 chars 👨⨝👩⨝👧, and rendering engines are free to either show them fused as one, or separately as three, depending on their abilities. Strings Description let s = "a"; A str is usually never held directly, but as &str , like s here. let s = "❤❤️"; It can hold arbitrary text, has variable length per c., and is hard to index. Encoding let s = "I ❤ Rust";

let t = "I ❤️ Rust"; Variant Memory Representation2 s.as_bytes() 49 20 e2 9d a4 20 52 75 73 74 3 s.chars() 1 49 00 00 00 20 00 00 00 64 27 00 00 20 00 00 00 52 00 00 00 75 00 00 00 73 00 ... t.as_bytes() 49 20 e2 9d a4 ef b8 8f 20 52 75 73 74 4 t.chars() 1 49 00 00 00 20 00 00 00 64 27 00 00 0f fe 01 00 20 00 00 00 52 00 00 00 75 00 ... 1 Result then collected into array and transmuted to bytes.

2 Values given in hex, on x86.

3 Notice how ❤ , having Unicode Code Point (U+2764), is represented as 64 27 00 00 inside the char , but got UTF-8 encoded to e2 9d a4 in the str .

4 Also observe how the emoji Red Heart ❤️ , is a combination of ❤ and the U+FE0F Variation Selector, thus t has a higher char count than s . 💬 For what seem to be browser bugs Safari and Edge render the hearts in Footnote 3 and 4 wrong, despite being able to differentiate them correctly in s and t above. Custom Typesurl Basic types definable by users. Actual layout REF is subject to representation; REF padding can be present. 1 T x T Sized ↓ T: ?Sized T Maybe DST ↓ (A, B, C) A B C struct S; ; Zero-Sized ↓ struct S { b: B, c: C } B C [T; n] T T T ... n times [T] ... T T T ... unspecified times These sum types hold a value of one of their sub types: enum E { A, B, C } Tag A exclusive or Tag B exclusive or Tag C Safely holds A or B or C, also

called 'tagged union', though

compiler may omit tag. union { ... } A unsafe or B unsafe or C Can unsafely reinterpret

memory. Result might

be undefined. 1 To be clear, the depiction of types here merely illustrates a random representation. Unless a certain one is forced (e.g., via #[repr(C)] , Rust will, for example, be free to layout A(u8, u16) as [u8 u16] and B(u8, u16) as [u16 u8] , even inside the same application! References & Pointersurl References give safe access to other memory, raw pointers unsafe access. For some referents additional payload may be present, see below. The respective mut types are identical. &'a T ptr 2/4/8 payload 2/4/8 | T During 'a any 'mem' this targets must

always be a valid t of T . *const T ptr 2/4/8 payload 2/4/8 No guarantees.

The payload depends on the base type of the referent. This applies to both references and pointers. &'a T ptr 2/4/8 | T &'a T ptr 2/4/8 len 2/4/8 | T If T is a DST struct such as

S { x: [u8] } field len is

length of dyn. sized content. &'a [T] ptr 2/4/8 len 2/4/8 | ... T T ... &'a str ptr 2/4/8 len 2/4/8 | ... U T F - 8 ...

&'a dyn Trait ptr 2/4/8 ptr 2/4/8 | T | *Drop::drop(&mut T) size align *Trait::f(&T, ...) *Trait::g(&T, ...) Where *Drop::drop() , *Trait::f() , ... are pointers to their respective impl for T . Closuresurl Closures are ad-hoc functions along with an automatically managed data block capturing REF the environment accessed where closure was defined. For example: move |x| x + y.f() + z Y Z Anonymous closure type C1 |x| x + y.f() + z ptr 2/4/8 ptr 2/4/8 Anonymous closure type C2 | Y | Z Also produces anonymous fn such as f_c1 (C1, X) or

f_c2 (&C2, X) . Details depend which FnOnce , FnMut , Fn ...

is supported, based on properties of captured types. Standard Library Typesurl Rust's standard library combines the above primitive types into useful types with special semantics, e.g.: UnsafeCell<T> T Magic type allowing

aliased mutability. Cell<T> T Allows T 's

to move in

and out. RefCell<T> borrowed T Also support dynamic

borrowing of T . Like Cell this

is Send , but not Sync . AtomicUsize usize 2/4/8 Other atomic similarly. Option<T> Tag or Tag T Tag may be omitted for

certain T. Result<T, E> Tag E or Tag T General Purpose Heap Storageurl Box<T> ptr 2/4/8 payload 2/4/8 | T Vec<T> ptr 2/4/8 capacity 2/4/8 len 2/4/8 | T T ... len ← capacity → Owned Stringsurl String ptr 2/4/8 capacity 2/4/8 len 2/4/8 | U T F - 8 ... len ← capacity → Observe how String differs from &str and &[char] . CString ptr 2/4/8 len 2/4/8 | A B C ... len ... ␀ Nul-terminated but w/o nul in middle. OsString ? Platform Defined | ? ? / ? ? PathBuf ? OsString | ? ? / ? ? Shared Ownershipurl If the type does not contain a Cell for T , these are often combined with one of the Cell types above to allow shared de-facto mutability. Rc<T> ptr 2/4/8 payload 2/4/8 | strng 2/4/8 weak 2/4/8 T Share ownership of T in same thread. Needs nested Cell

or RefCell to allow mutation. Is neither Send nor Sync . Arc<T> ptr 2/4/8 payload 2/4/8 | strng 2/4/8 weak 2/4/8 T Same, but allow sharing between threads IF contained

T itself is Send and Sync .

Mutex<T> / RwLock<T> ptr 2/4/8 poison 2/4/8 T | lock Needs to be held in Arc to be shared between

threads, always Send and Sync . Consider using

parking_lot instead (faster, no heap usage).

Standard Libraryurl

Common One-Linersurl

Snippets that are common, but still easy to forget. See Rust Cookbook 🔗 for more.

Intent Snippet Create a new file File::create(PATH)? Same, via OpenOptions* OpenOptions::new().create(t).write(t).truncate(t).open(PATH)? Fix inference in ' try ' closures iter.try_for_each(|x| { Ok::<(), Error>(()) })?; Macro w. variable arguments macro_rules! var_args { ($($args:expr),*) => {{ }} } Using the arguments $( f($args); )* Iterate and edit &mut [T] if T Copy. Cell::from_mut(mut_slice).as_slice_of_cells() * We're a bit short on space here, t means true.

Traitsurl

Traits define common behavior. If S implements trait T , you know S can behave as prescribed by T . Below is an overview of traits that may be more tricky.

🧵 Thread Safetyurl

Examples Send * !Send Sync * Most types ... Mutex<T> , Arc<T> 1,2 MutexGuard<T> 1, RwLockReadGuard<T> 1 !Sync Cell<T> 2, RefCell<T> 2 Rc<T> , Formatter , &dyn Trait

* An instance t where T: Send can be moved to another thread, a T: Sync means &t can be moved to another thread.

1 If T is Sync .

2 If T is Send .

🐘 (Dynamically / Zero) Sized Typesurl

Overview A type T is Sized STD if at compile time it is known how many bytes it occupies, u8 and &[u8] are, [u8] isn't.

is if at compile time it is known how many bytes it occupies, and are, isn't. Being Sized means impl Sized for T {} holds. Happens automatically and cannot be user impl'ed.

means holds. Happens automatically and cannot be user impl'ed. Types not Sized are called dynamically sized types BK NOM REF (DSTs), sometimes unsized .

are called (DSTs), sometimes . Types without data are called zero sized types NOM (ZSTs), do not occupy space. Sized in Bounds Example Explanation struct A { x: u8 } Type A is sized, i.e., impl Sized for A holds, this is a 'regular' type. struct B { x: [u8] } Since [u8] is a DST, B in turn becomes DST, i.e., does not impl Sized . struct C<T> { x: T } Type params have implicit T: Sized bound, e.g., C<A> is valid, C<B> is not. struct D<T: ?Sized> { x: T } Using ?Sized REF allows opt-out of that bound, i.e., D<B> is also valid. struct E; Type E is zero-sized (and also sized) and will not consume memory. trait F { fn f(&self); } Traits do not have an implicit Sized bound, i.e., impl F for B {} is valid. trait F: Sized {} Traits can however opt into Sized via supertraits.↑ trait G { fn g(self); } For Self -like params DST impl may still fail as params can't go on stack.

🚥 Iteratorsurl

Using Iterators Basics Assume you have a collection c of type C : c.into_iter() — Turns collection c into an Iterator STD i and consumes * c . Requires IntoIterator STD for C to be implemented. Type of item depends on what C was. 'Standardized' way to get Iterators.

— Turns collection into an and . Requires for to be implemented. Type of item depends on what was. 'Standardized' way to get Iterators. c.iter() — Courtesy method some collections provide, returns borrowing Iterator, doesn't consume c .

— Courtesy method collections provide, returns Iterator, doesn't consume . c.iter_mut() — Same, but mutably borrowing Iterator that allow collection to be changed. The Iterator Once you have an i : i.next() — Returns Some(x) next element c provides, or None if we're done. For Loops for x in c {} — Syntactic sugar, calls c.into_iter() and loops i until None . * If it looks as if it doesn't consume c that's because type was Copy . For example, if you call (&c).into_iter() it will invoke .into_iter() on &c (which will consume the reference and turn it into an Iterator), but c remains untouched. Implementing Iterators Basics Let's assume you have a struct C {} that is your collection. struct Iter {} — Create a struct to hold your iteration status (e.g., an index) for immutable iteration.

— Create a struct to hold your iteration status (e.g., an index) for immutable iteration. impl Iterator for Iter {} — Provide an implementation of Iterator::next() so it can produce elements. In addition, you might want to add a convenience fn iter(&self) -> Iter inside your impl C {} . Mutable Iterators struct IterMut {} — To provide mutable iterators create another struct that can hold C as &mut .

— To provide mutable iterators create another struct that can hold as . impl Iterator for IterMut {} — In that case Iterator::Item is probably a &mut item Similarly, providing a fn iter_mut(&mut self) -> IterMut might be a good idea. Making Loops Work impl IntoIterator for C {} — Now for loops work as for x in c {} .

— Now loops work as . impl IntoIterator for &C {} — For conveninece you might want to add these as well.

— For conveninece you might want to add these as well. impl IntoIterator for &mut C {} — Same ...

Number Conversionsurl

As-correct-as-it-currently-gets number conversions.

↓ Have / Want → u8 ... i128 f32 / f64 String u8 ... i128 u8::try_from(x)? 1 x as f32 3 x.to_string() f32 / f64 x as u8 2 x as f32 x.to_string() String x.parse::<u8>()? x.parse::<f32>()? x

1 If type true subset from() works directly, e.g., u32::from(my_u8) .

2 Truncating ( 11.9_f32 as u8 gives 11 ) and saturating ( 1024_f32 as u8 gives 255 ).

3 Might misrepresent number ( u64::MAX as f32 ) or produce Inf ( u128::MAX as f32 ).

String Conversionsurl

If you want a string of type ...

String If you have x of type ... Use this ... String x CString x.into_string()? OsString x.to_str()?.to_string() PathBuf x.to_str()?.to_string() Vec<u8> 1 String::from_utf8(x)? &str x.to_string() i &CStr x.to_str()?.to_string() &OsStr x.to_str()?.to_string() &Path x.to_str()?.to_string() &[u8] 1 String::from_utf8_lossy(x).to_string() CString If you have x of type ... Use this ... String CString::new(x)? CString x OsString 2 CString::new(x.to_str()?)? PathBuf CString::new(x.to_str()?)? Vec<u8> 1 CString::new(x)? &str CString::new(x)? &CStr x.to_owned() i &OsStr 2 CString::new(x.to_os_string().into_string()?)? &Path CString::new(x.to_str()?)? &[u8] 1 CString::new(Vec::from(x))? *mut c_char 3 unsafe { CString::from_raw(x) } OsString If you have x of type ... Use this ... String OsString::from(x) i CString OsString::from(x.to_str()?) OsString x PathBuf x.into_os_string() Vec<u8> 1 ? &str OsString::from(x) i &CStr OsString::from(x.to_str()?) &OsStr OsString::from(x) i &Path x.as_os_str().to_owned() &[u8] 1 ? PathBuf If you have x of type ... Use this ... String PathBuf::from(x) i CString PathBuf::from(x.to_str()?) OsString PathBuf::from(x) i PathBuf x Vec<u8> 1 ? &str PathBuf::from(x) i &CStr PathBuf::from(x.to_str()?) &OsStr PathBuf::from(x) i &Path PathBuf::from(x) i &[u8] 1 ? Vec<u8> If you have x of type ... Use this ... String x.into_bytes() CString x.into_bytes() OsString ? PathBuf ? Vec<u8> 1 x &str Vec::from(x.as_bytes()) &CStr Vec::from(x.to_bytes_with_nul()) &OsStr ? &Path ? &[u8] 1 x.to_vec() &str If you have x of type ... Use this ... String x.as_str() CString x.to_str()? OsString x.to_str()? PathBuf x.to_str()? Vec<u8> 1 std::str::from_utf8(&x)? &str x &CStr x.to_str()? &OsStr x.to_str()? &Path x.to_str()? &[u8] 1 std::str::from_utf8(x)? &CStr If you have x of type ... Use this ... String CString::new(x)?.as_c_str() CString x.as_c_str() OsString 2 x.to_str()? PathBuf ?,4 Vec<u8> 1,5 CStr::from_bytes_with_nul(&x)? &str ?,4 &CStr x &OsStr 2 ? &Path ? &[u8] 1,5 CStr::from_bytes_with_nul(x)? *const c_char 1 unsafe { CStr::from_ptr(x) } &OsStr If you have x of type ... Use this ... String OsStr::new(&x) CString ? OsString x.as_os_str() PathBuf x.as_os_str() Vec<u8> 1 ? &str OsStr::new(x) &CStr ? &OsStr x &Path x.as_os_str() &[u8] 1 ? &Path If you have x of type ... Use this ... String Path::new(x) r CString Path::new(x.to_str()?) OsString Path::new(x.to_str()?) r PathBuf Path::new(x.to_str()?) r Vec<u8> 1 ? &str Path::new(x) r &CStr Path::new(x.to_str()?) &OsStr Path::new(x) r &Path x &[u8] 1 ? &[u8] If you have x of type ... Use this ... String x.as_bytes() CString x.as_bytes() OsString ? PathBuf ? Vec<u8> 1 &x &str x.as_bytes() &CStr x.to_bytes_with_nul() &OsStr x.as_bytes() 2 &Path ? &[u8] 1 x Other You want And have x Use this ... *const c_char CString x.as_ptr()

i Short form x.into() possible if type can be inferred.

r Short form x.as_ref() possible if type can be inferred. 1 You should, or must if call is unsafe , ensure raw data comes with a valid representation for the string type (e.g., UTF-8 data for a String ). 2 Only on some platforms std::os::<your_os>::ffi::OsStrExt exists with helper methods to get a raw &[u8] representation of the underlying OsStr . Use the rest of the table to go from there, e.g.: use std::os::unix::ffi::OsStrExt; let bytes: &[u8] = my_os_str.as_bytes(); CString::new(bytes)? 3 The c_char must have come from a previous CString . If it comes from FFI see &CStr instead. 4 No known shorthand as x will lack terminating 0x0 . Best way to probably go via CString . 5 Must ensure vector actually ends with 0x0 .

String Formattingurl

Formatting applies to print! , eprint! , write! (and their - ln siblings like println! ). Each format argument is either empty {} , {argument} , or follows a basic syntax:

{ [argument] ':' [[fill] align] [sign] ['#'] [width [$]] ['.' precision [$]] [type] }

Element Meaning argument Number ( 0 , 1 , ...) or argument name, e.g., print!("{x}", x = 3) . fill The character to fill empty spaces with (e.g., 0 ), if width is specified. align Left ( < ), center ( ^ ), or right ( > ), if width is specified. sign Can be + for sign to always be printed. # Alternate formatting, e.g. prettify Debug ? or prefix hex with 0x . width Minimum width (≥ 0), padding with fill (default to space). If starts with 0 , zero-padded. precision Decimal digits (≥ 0) for numerics, or max width for non-numerics. $ Interpret width or precision as argument identifier instead to allow for dynamic formatting. type Debug ( ? ) formatting, hex ( x ), binary ( b ), octal ( o ), pointer ( p ), exp ( e ) ... see more.

Example Explanation {:?} Print the next argument using Debug. {2:#?} Pretty-print the 3rd argument with Debug formatting. {val:^2$} Center the val named argument, width specified by the 3rd argument. {:<10.3} Left align with width 10 and a precision of 3. {val:#x} Format val argument as hex, with a leading 0x (alternate format for x ).

Toolingurl

Project Anatomyurl

Basic project layout, and common files and folders, as used by cargo . ↓

Entry Code 📁 benches/ Benchmarks for your crate, run via cargo bench , requires nightly by default. * 🚧 📁 examples/ Examples how to use your crate, they see your crate like external user would. my_example.rs Individual examples are run like cargo run --example my_example . 📁 src/ Actual source code for your project. build.rs Pre-build script 🔗, e.g., when compiling C / FFI, needs to be specified in Cargo.toml . main.rs Default entry point for applications, this is what cargo run uses. lib.rs Default entry point for libraries. This is where lookup for my_crate::f() starts. 📁 tests/ Integration tests go here, invoked via cargo test . Unit tests often stay in src/ file. .rustfmt.toml In case you want to customize how cargo fmt works. .clippy.toml Special configuration for certain clippy lints, utilized via cargo clippy Cargo.toml Main project configuration. Defines dependencies, artifacts ... Cargo.lock Dependency details for reproducible builds, recommended to git for apps, not for libs.

* On stable consider Criterion.

Minimal examples for various entry points might look like: Applications // src/main.rs (default application entry point) fn main() { println!("Hello, world!"); } Libraries // src/lib.rs (default library entry point) pub fn f() {} // Is a public item in root, so it's accessible from the outside. mod m { pub fn g() {} // No public path (`m` not public) from root, so `g` } // is not accessible from the outside of the crate. Proc Macros // src/lib.rs (default entry point for proc macros) extern crate proc_macro; // Apparently needed to be imported like this. use proc_macro::TokenStream; #[proc_macro_attribute] // Can now be used as `#[my_attribute]` pub fn my_attribute(_attr: TokenStream, item: TokenStream) -> TokenStream { item } // Cargo.toml [package] name = "my_crate" version = "0.1.0" [lib] crate_type = ["proc-macro"] Unit Tests // src/my_module.rs (any file of your project) fn f() -> u32 { 0 } #[cfg(test)] mod test { use super::f; // Need to import items from parent module. Has // access to non-public members. #[test] fn ff() { assert_eq!(f(), 0); } } Integration Tests // tests/sample.rs (sample integration test) #[test] fn my_sample() { assert_eq!(my_crate::f(), 123); // Integration tests (and benchmarks) 'depend' to the crate like } // a 3rd party would. Hence, they only see public items. Benchmarks // benches/sample.rs (sample benchmark) #![feature(test)] // #[bench] is still experimental extern crate test; // Even in '18 this is needed ... for reasons. // Normally you don't need this in '18 code. use test::{black_box, Bencher}; #[bench] fn my_algo(b: &mut Bencher) { b.iter(|| black_box(my_crate::f())); // `black_box` prevents `f` from being optimized away. } Build Scripts // src/build.rs (sample pre-build script) // Also specify in `Cargo.toml` like this: // [package] // build = "src/build.rs" fn main() { // You need to rely on env. vars for target; `#[cfg(...)]` are for host. let target_os = env::var("CARGO_CFG_TARGET_OS"); } *See here for list of environment variables set.

Modules BK EX REF and source files work as follows:

Module tree needs to be explicitly defined, is not implicitly built from file system tree . 🔗

needs to be explicitly defined, is not implicitly built from . Module tree root equals library, app, ... entry point (e.g., lib.rs ).

equals library, app, ... entry point (e.g., ). A mod m {} defines module in-file, while mod m; will read m.rs or m/mod.rs . Path of .rs based on nesting, e.g., mod a { mod b { mod c; }}} is either a/b/c.rs or a/b/c/mod.rs . Files not pathed from module tree root via some mod m; won't be touched by compiler! 🛑

defines module in-file, while will read or .

Cargourl

Commands and tools that are good to know.

Command Description cargo init Create a new project for the latest edition. cargo b uild Build the project in debug mode ( --release for all optimization). cargo c heck Check if project would compile (much faster). cargo t est Run tests for the project. cargo r un Run your project, if a binary is produced (main.rs). cargo run --bin b Run binary b . Unifies features with other dependents (can be confusing). cargo run -p w Run main of sub-workspace w . Treats features more as you would expect. cargo doc --open Locally generate documentation for your code and dependencies. cargo rustc -- -Zunpretty=X Show more desugared Rust code, in particular with X being: expanded Show with expanded macros, ... cargo +{nightly, stable} ... Runs command with given toolchain, e.g., for 'nightly only' tools. rustup doc Open offline Rust documentation (incl. the books), good on a plane!

A command like cargo build means you can either type cargo build or just cargo b .

These are optional rustup components. Install them with rustup component add [tool] .

Tool Description cargo clippy Additional (lints) catching common API misuses and unidiomatic code. 🔗 cargo fmt Automatic code formatter ( rustup component add rustfmt ). 🔗

A large number of additional cargo plugins can be found here.

Cross Compilationurl

🔘 Check target is supported. 🔘 Install target via rustup target install X . 🔘 Install native toolchain (required to link, depends on target). Get from target vendor (Google, Apple, ...), might not be available on all hosts (e.g., no iOS toolchain on Windows). Some toolchains require additional build steps (e.g., Android's make-standalone-toolchain.sh ). 🔘 Update ~/.cargo/config.toml like this: [target.aarch64-linux-android] linker = "[PATH_TO_TOOLCHAIN]/aarch64-linux-android/bin/aarch64-linux-android-clang" or [target.aarch64-linux-android] linker = "C:/[PATH_TO_TOOLCHAIN]/prebuilt/windows-x86_64/bin/aarch64-linux-android21-clang.cmd" 🔘 Set environment variables (optional, wait until compiler complains before setting): set CC=C:\[PATH_TO_TOOLCHAIN]\prebuilt\windows-x86_64\bin\aarch64-linux-android21-clang.cmd set AR=C:\[PATH_TO_TOOLCHAIN]\prebuilt\windows-x86_64\bin\aarch64-linux-android-ar.exe ... Whether you set them depends on how compiler complains, not necessarily all are needed. Some platforms / configurations can be extremely sensitive how paths are specified (e.g., \ vs / ) and quoted. ✔️ Compile with cargo build --target=X

Coding Guidesurl

Idiomatic Rusturl

If you are used to programming Java or C, consider these.

Idiom Code Think in Expressions x = if x { a } else { b }; x = loop { break 5 }; fn f() -> u32 { 0 } Think in Iterators (1..10).map(f).collect() names.iter().filter(|x| x.starts_with("A")) Handle Absence with ? x = try_something()?; get_option()?.run()? Use Strong Types enum E { Invalid, Valid { ... } } over ERROR_INVALID = -1 enum E { Visible, Hidden } over visible: bool struct Charge(f32) over f32 Provide Builders Car::new("Model T").hp(20).build(); Split Implementations Generic types S<T> can have a separate impl per T . Rust doesn't have OO, but with separate impl you can get specialization. Unsafe Avoid unsafe {} , often safer, faster solution without it. Exception: FFI. Implement Traits #[derive(Debug, Copy, ...)] and custom impl where needed. Tooling With clippy you can improve your code quality. Formatting with rustfmt helps others to read your code. Add unit tests BK ( #[test] ) to ensure your code works. Add doc tests BK ( ``` my_api::f() ``` ) to ensure docs match code. Documentation Annotate your APIs with doc comments that can show up on docs.rs. Don't forget to include a summary sentence and the Examples heading. If applicable: Panics, Errors, Safety, Abort and Undefined Behavior.

🔥 We highly recommend you also follow the API Guidelines (Checklist) for any shared project! 🔥

Async-Await 101url

If you are familiar with async / await in C# or TypeScript, here are some things to keep in mind:

Basics Construct Explanation async Anything declared async always returns an impl Future<Output=_> . STD async fn f() {} Function f returns an impl Future<Output=()> . async fn f() -> S {} Function f returns an impl Future<Output=S> . async { x } Transforms { x } into an impl Future<Output=X> . let sm = f(); Calling f() that is async will not execute f , but produce state machine sm . 1 2 sm = async { g() }; Likewise, does not execute the { g() } block; produces state machine. runtime.block_on(sm); Outside an async {} , schedules sm to actually run. Would execute g() . 3 4 sm.await Inside an async {} , run sm until complete. Yield to runtime if sm not ready. 1 Technically async transforms following code into anonymous, compiler-generated state machine type; f() instantiates that machine.

2 The state machine always impl Future , possibly Send & co, depending on types used inside async .

3 State machine driven by worker thread invoking Future::poll() via runtime directly, or parent .await indirectly.

4 Rust doesn't come with runtime, need external crate instead, e.g., async-std or tokio 0.2+. Also, more helpers in futures crate. Execution Flow At each x.await , state machine passes control to subordinate state machine x . At some point a low-level state machine invoked via .await might not be ready. In that the case worker thread returns all the way up to runtime so it can drive another Future. Some time later the runtime: might resume execution. It usually does, unless sm / Future dropped.

resume execution. It usually does, unless / dropped. might resume with the previous worker or another worker thread (depends on runtime). Simplified diagram for code written inside an async block : consecutive_code(); consecutive_code(); consecutive_code(); START --------------------> x.await --------------------> y.await --------------------> READY // ^ ^ ^ Future<Output=X> ready -^ // Invoked via runtime | | // or an external .await | This might resume on another thread (next best available), // | or NOT AT ALL if Future was dropped. // | // Execute `x`. If ready: just continue execution; if not, return // this thread to runtime. Caveats With the execution flow in mind, some considerations when writing code inside an async construct: Constructs 1 Explanation sleep_or_block(); Definitely bad 🛑, never halt current thread, clogs executor. set_TL(a); x.await; TL(); Definitely bad 🛑, await may return from other thread, thread local invalid. s.no(); x.await; s.go(); Maybe bad 🛑, await will not return if Future dropped while waiting. 2 Rc::new(); x.await; rc(); Non- Send types prevent impl Future from being Send ; less compatible. 1 Here we assume s is any non-local that could temporarily be put into an invalid state; TL is any thread local storage, and that the async {} containing the code is written without assuming executor specifics.

2 Since Drop is run in any case when Future is dropped, consider using drop guard that cleans up / fixes application state if it has to be left in bad condition across .await points.

Closures in APIsurl

There is a subtrait relationship Fn : FnMut : FnOnce . That means a closure that implements Fn STD also implements FnMut and FnOnce . Likewise a closure that implements FnMut STD also implements FnOnce . STD

From a call site perspective that means:

Signature Function g can call ... Function g accepts ... g<F: FnOnce()>(f: F) ... f() once. Fn , FnMut , FnOnce g<F: FnMut()>(mut f: F) ... f() multiple times. Fn , FnMut g<F: Fn()>(f: F) ... f() multiple times. Fn

Notice how asking for a Fn closure as a function is most restrictive for the caller; but having a Fn closure as a caller is most compatible with any function.

From the perspective of someone defining a closure:

Closure Implements* Comment || { moved_s; } FnOnce Caller must give up ownership of moved_s . || { &mut s; } FnOnce , FnMut Allows g() to change caller's local state s . || { &s; } FnOnce , FnMut , Fn May not mutate state; but can share and reuse s .

That gives the following advantages and disadvantages:

Requiring Advantage Disadvantage F: FnOnce Easy to satisfy as caller. Single use only, g() may call f() just once. F: FnMut Allows g() to change caller state. Caller may not reuse captures during g() . F: Fn Many can exist at same time. Hardest to produce for caller.

Unsafe, Unsound, Undefinedurl

Unsafe leads to unsound. Unsound leads to undefined. Undefined leads to the dark side of the force.

Unsafe Code Unsafe Code Code marked unsafe has special permissions, e.g., to deref raw pointers, or invoke other unsafe functions.

has special permissions, e.g., to deref raw pointers, or invoke other functions. Along come special promises the author must uphold to the compiler , and the compiler will trust you.

, and the compiler will trust you. By itself unsafe code is not bad, but dangerous, and needed for FFI or exotic data structures. // `x` must always point to race-free, valid, aligned, initialized u8 memory. unsafe fn unsafe_f(x: *mut u8) { my_native_lib(x); } Undefined Behavior Undefined Behavior (UB) As mentioned, unsafe code implies special promises to the compiler (it wouldn't need be unsafe otherwise).

code implies special promises to the compiler (it wouldn't need be otherwise). Failure to uphold any promise makes compiler produce fallacious code, execution of which leads to UB.

After triggering undefined behavior anything can happen. Insidiously, the effects may be 1) subtle, 2) manifest far away from the site of violation or 3) be visible only under certain conditions.

A seemingly working program (incl. any number of unit tests) is no proof UB code might not fail on a whim.

Code with UB is objectively dangerous, invalid and should never exist. if maybe_true() { let r: &u8 = unsafe { &*ptr::null() }; // Once this runs, ENTIRE app is undefined. Even if } else { // line seemingly didn't do anything, app might now run println!("the spanish inquisition"); // both paths, corrupt database, or anything else. } Unsound Code Unsound Code Any safe Rust that could (even only theoretically) produce UB for any user input is always unsound .

. As is unsafe code that may invoke UB on its own accord by violating above-mentioned promises.

code that may invoke UB on its own accord by violating above-mentioned promises. Unsound code is a stability and security risk, and violates basic assumption many Rust users have. fn unsound_ref<T>(x: &T) -> &u128 { // Signature looks safe to users. Happens to be unsafe { mem::transmute(x) } // ok if invoked with an &u128, UB for practically } // everything else.

Responsible use of Unsafe Do not use unsafe unless you absolutely have to.

unless you absolutely have to. Follow the Nomicon, Unsafe Guidelines, always uphold all safety invariants, and never invoke UB.

uphold safety invariants, and invoke UB. Minimize the use of unsafe and encapsulate it in small, sound modules that are easy to review.

and encapsulate it in small, sound modules that are easy to review. Each unsafe unit should be accompanied by plain-text reasoning outlining its safety.

API Stabilityurl

When updating an API, these changes can break client code.RFC Major changes (🔴) are definitely breaking, while minor changes (🟡) might be breaking: