DEV Community

Cover image for Rust cheatsheet examples part_1
Stanislav Kniazev
Stanislav Kniazev

Posted on

Rust cheatsheet examples part_1

Basic Types & Variables

Boolean
  • bool - Boolean (true or false)
Unsigned integers
  • u8, u16, u32, u64, u128
Signed integers
  • i8, i16, i32, i64, i128
Floating point numbers
  • f32, f64
Platform specific integers
  • usize - Unsigned integer. Same number of bits as the platform's pointer type.
  • isize - Signed integer. Same number of bits as the platform's pointer type.
Characters and Strings
  • char - Unicode scalar value
  • &str - String slice
  • String - Owned string
Null / Nil

Rust doesn’t have the null feature that many other languages have. Null is a value that means there is no value there. Rust does have an enum that can encode the concept of a value being present or absent. This enum is Option<T>, and it is defined by the standard library as follows:

enum Option<T> {     
  Some(T), 
  None
}
Enter fullscreen mode Exit fullscreen mode

You can use Some and None directly without the Option:: prefix. The Option<T> enum is still just a regular enum, and Some(T) and None are still variants of type Option<T>.

Tuple
let coordinates = (82, 64);
let score = ("Team A", 12);
Enter fullscreen mode Exit fullscreen mode
Array & Slice

Slices are similar to arrays, but their length is not known at compile time. Instead, a slice is a two-word object; the first word is a pointer to the data, the second word is the length of the slice

let nums = [1, 2, 3, 4, 5];
let zeros = [0; 4]; // [0, 0, 0, 0]
let slice = &nums[1..4];

Enter fullscreen mode Exit fullscreen mode
Hashmap
use std::collections::HashMap;

let mut scores = HashMap::new();
scores.insert(String::from("Team1"), 900);
scores.entry("Team2".to_owned()).or_insert(250);
Enter fullscreen mode Exit fullscreen mode
Struct
struct Person {
    name: String,
    is_active: bool,
}

let person1 = Person {
    name: String::from("alex"),
    is_active: false,
};

struct Point(i32, i32, i32);
let white = Point(255, 255, 255);
Enter fullscreen mode Exit fullscreen mode
Enum
enum Action {
    Stop,
    Go { x: i32, y: i32 },
    Yell(String),
    ChangeColor(i32, i32, i32),
}

let act1 = Action::Stop;
let act2 = Action::Go { x: 10, y: 20 };
let act3 = Action::Yell("Hello".to_owned());
let act4 = Action::ChangeColor(255, 255, 0);
Enter fullscreen mode Exit fullscreen mode
Constant
const MAX_SCORE: u32 = 10000;
Enter fullscreen mode Exit fullscreen mode
Static variable
static APP_VERSION: u32 = 1;
static mut HIT_COUNT: u32 = 0;
Enter fullscreen mode Exit fullscreen mode
Mutability
let mut val = 5; 
val = 7;
Enter fullscreen mode Exit fullscreen mode
Shadowing
let val = 5; 
let val = val + 2;
Enter fullscreen mode Exit fullscreen mode
Type alias type Score = u64;

Control Flow

if and if-let

let maybe_num = Some(7);

if maybe_num.is_some() {
    println!("number is: {}", maybe_num.unwrap());
}

// `if let` allows various failure options to be specified:
if let Some(i) = letter {
    println!("Matched {:?}!", i);
} else {
    // Destructure failed. Change to the failure case.
    println!("Didn't match a number. Let's go with a letter!");
}
Enter fullscreen mode Exit fullscreen mode

let-else

With let-else, a refutable pattern can match and bind variables in the surrounding scope like a normal let, or else diverge (e.g. breakreturnpanic!) when the pattern doesn't match.
The scope of name bindings is the main thing that makes this different from match or if let-else expressions.

let (Some(count_str), Some(item)) = (it.next(), it.next()) else { 
  panic!("Can't segment count item pair: '{s}'");
}; 

let Ok(count) = u64::from_str(count_str) else { 
    panic!("Can't parse integer: '{count_str}'"); 
};
Enter fullscreen mode Exit fullscreen mode

while-let

while let can make awkward match sequences more tolerable.

let mut optional = Some(0);

// This reads: "while `let` destructures `optional` into
// `Some(i)`, evaluate the block (`{}`). Else `break`.
while let Some(i) = optional {
    if i > 9 {
        println!("Greater than 9, quit!");
        optional = None;
    } else {
        println!("`i` is `{:?}`. Try again.", i);
        optional = Some(i + 1);
    } // Doesn't require explicitly handling the failing case.
}
Enter fullscreen mode Exit fullscreen mode

Loops

let mut counter = 0;
loop {
    counter += 1;
    if counter == 3 {
        break; // Exit loop
    }
}

let mut count = 0;
let result = loop {
    count += 1;
    if count == 5 {
        break count; // Return value from loop
    }
};

let mut num = 0;
while num < 50 {
    num += 1;
}
Enter fullscreen mode Exit fullscreen mode

Nested loops & labels

'outer: loop {
    'inner: loop {
        break; // This breaks the inner loop
        break 'outer; // This breaks the outer loop
    }
}
Enter fullscreen mode Exit fullscreen mode

for loop

for n in 1..=101 {
    if n % 15 == 0 {
        println!("fizzbuzz");
    } else if n % 3 == 0 {
        println!("fizz");
    } else if n % 5 == 0 {
        println!("buzz");
    } else {
        println!("{}", n);
    }
}
Enter fullscreen mode Exit fullscreen mode

for loop takes ownership of v1_iter and makes it mutable behind the scenes.

let v1 = vec![1, 2, 3]; 
let v1_iter = v1.iter(); 

for val in v1_iter { 
  println!("Got: {}", val); 
}
Enter fullscreen mode Exit fullscreen mode

Pattern Matching ❤️

Rust provides powerful pattern matching capabilities through the match expression and if let syntax, which can destructure, test, and compare values in a clean and concise way.

let x = 3;
match x {  
    1 => println!("one"),  
    2 | 3 => println!("two or three"),  // multiple values
    4..=9 => println!("within range"), // matching ranges  
    x => println!("{}", x),  // matching named variables  
    _ => println!("default Case") // default case (ignores value)  
}

// Another example:
let option_value = Some(5); 

match option_value { 
  Some(value) => println!("The value is: {}", value), 
  None => println!("The value is missing"), 
} 
if let Some(value) = option_value { println!("The value is: {}", value); }

Enter fullscreen mode Exit fullscreen mode

Destructuring

match block can be used to destructure Tuples, Arrays/Slices, Enums, Pointers, Structs.

enum Color {
    Red,
    Blue,
    Green,
    RGB(u32, u32, u32),
    CMYK(u32, u32, u32, u32),
}

fn main() {
    let color = Color::RGB(122, 17, 40);

    println!("What color is it?");
    match color {
        Color::Red   => println!("The color is Red!"),
        Color::Blue  => println!("The color is Blue!"),
        Color::Green => println!("The color is Green!"),
        Color::RGB(r, g, b) =>
            println!("Red: {}, green: {}, and blue: {}!", r, g, b),
        Color::CMYK(c, m, y, k) =>
            println!("Cyan: {}, magenta: {}, yellow: {}, key (black): {}!",
                c, m, y, k),
        ...
    }
}


Part 2 is coming soon.

let array = [1, -2, 6];

match array {
    // Binds the second and the third elements to the respective variables
    [0, second, third] =>
        println!("array[0] = 0, array[1] = {}, array[2] = {}", second, third),

    // Single values can be ignored with _
    [1, _, third] => println!(
        "array[0] = 1, array[2] = {} and array[1] was ignored",
        third
    ),
    ...
}
Enter fullscreen mode Exit fullscreen mode

More fun stuff - Destructuring examples

Binding

Indirectly accessing a variable makes it impossible to branch and use that variable without re-binding. match provides the @ sigil for binding values to names:

fn some_number() -> Option<u32> {
    Some(42)
}

fn main() {
    match some_number() {
        // Got `Some` variant, match if its value, bound to `n`,
        // is equal to 42.
        Some(n @ 42) => println!("The Answer: {}!", n),
        // Match any other number.
        Some(n)      => println!("Not interesting... {}", n),
        // Match anything else (`None` variant).
        _            => (),
    }
}
Enter fullscreen mode Exit fullscreen mode

Part 2 is coming soon!

Top comments (0)