Literals and operators Integers 1, floats 1.2, characters 'a', strings "abc", booleans true and the unit type () can be expressed using literals. Integers can, alternatively, be expressed using hexadecimal, octal or binary notation using th...
Tuples A tuple is a collection of values of different types. Tuples are constructed using parentheses (), and each tuple itself is a value with type signature (T1, T2, ...), where T1, T2 are the types of its members. Functions can use tuple...
Arrays and Slices An array is a collection of objects of the same type T, stored in contiguous memory. Arrays are created using brackets [], and their length, which is known at compile time, is part of their type signature [T; length]. Slic...
Custom Types Rust custom data types are formed mainly through the two keywords: • struct: define a structure • enum: define an enumeration Constants can also be created via the const and static keywords.
Structures There are three types of structures ("structs") that can be created using the struct keyword: • Tuple structs, which are, basically, named tuples. • The classic C structs • Unit structs, which are field-less, are useful for gener...
Enums The enum keyword allows the creation of a type which may be one of a few different variants. Any variant which is valid as a struct is also valid in an enum. // Create an `enum` to classify a web event. Note how both // names and type...
use The use declaration can be used to avoid typing the full module path to access a name: // An attribute to hide warnings for unused code. #![allow(dead_code)] enum Stage { Beginner, Advanced, } enum Role { Student, Teacher, } fn main() {...
C-like enum can also be used as C-like enums. // An attribute to hide warnings for unused code. #![allow(dead_code)] // enum with implicit discriminator (starts at 0) enum Number { Zero, One, Two, } // enum with explicit discriminator enum...
Testcase: linked-list A common way to implement a linked-list is via enums: use crate::List::*; enum List { // Cons: Tuple struct that wraps an element and a pointer to the next node Cons(u32, Box<List>), // Nil: A node that signifies the e...
constants Rust has two different types of constants which can be declared in any scope including global. Both require explicit type annotation: • const: An unchangeable value (the common case). • static: A possibly mutable variable with 'st...
Variable Bindings Rust provides type safety via static typing. Variable bindings can be type annotated when declared. However, in most cases, the compiler will be able to infer the type of the variable from the context, heavily reducing the...
Mutability Variable bindings are immutable by default, but this can be overridden using the mut modifier. fn main() { let _immutable_binding = 1; let mut mutable_binding = 1; println!("Before mutation: {}", mutable_binding); // Ok mutable_b...
Scope and Shadowing Variable bindings have a scope, and are constrained to live in a block. A block is a collection of statements enclosed by braces {}. fn main() { // This binding lives in the main function let long_lived_binding = 1; // T...
Declare first It is possible to declare variable bindings first and initialize them later, but all variable bindings must be initialized before they are used: the compiler forbids use of uninitialized variable bindings, as it would lead to...
Freezing When data is bound by the same name immutably, it also freezes. Frozen data can't be modified until the immutable binding goes out of scope: fn main() { let mut _mutable_integer = 7i32; { // Shadowing by immutable `_mutable_integer...
Types Rust provides several mechanisms to change or define the type of primitive and user defined types. The following sections cover: • Casting between primitive types • Specifying the desired type of literals • Using type inference • Alia...
Casting Rust provides no implicit type conversion (coercion) between primitive types. But, explicit type conversion (casting) can be performed using the as keyword. Rules for converting between integral types follow C conventions generally,...
Literals Numeric literals can be type annotated by adding the type as a suffix. As an example, to specify that the literal 42 should have the type i32, write 42i32. The type of unsuffixed numeric literals will depend on how they are used. I...
Inference The type inference engine is pretty smart. It does more than looking at the type of the value expression during an initialization. It also looks at how the variable is used afterwards to infer its type. Here's an advanced example...
Aliasing The type statement can be used to give a new name to an existing type. Types must have UpperCamelCase names, or the compiler will raise a warning. The exception to this rule are the primitive types: usize, f32, etc. // `NanoSecond`...