Rust Cheatsheet

This is a cheatsheet for rust.

Installation

sudo apt update && sudo apt install cargo -y

Hello World

# Create a new project first.
cargo new hello_world

# Go to the project dir.
cd hello_world

# Compile the source code.
cargo build

# Run the code
cargo run

Source Code

The source code of the hello world program is

fn main() {
    println!("Hello, world!");
}

Basics

Variables

x : i32 = 1; // An i32 variable.

x : bool = true; // A boolean variable.

x : f32 = 1.2; // A float 32 variable.

All variable data types:

DataTypeDescription
boolThe boolean type.
charA character type.
i8The 8-bit signed integer type.
i16The 16-bit signed integer type.
i32The 32-bit signed integer type.
i64The 64-bit signed integer type.
isizeThe pointer-sized signed integer type.
u8The 8-bit unsigned integer type.
u16The 16-bit unsigned integer type.
u32The 32-bit unsigned integer type.
u64The 64-bit unsigned integer type.
usizeThe pointer-sized unsigned integer type.
f32The 32-bit floating point type.
f64The 64-bit floating point type.
arrayA fixed-size array, denoted [T; N], for the element type, T, and the non-negative compile-time constant size, N.
sliceA dynamically-sized view into a contiguous sequence, [T].
strString slices.
tupleA finite heterogeneous sequence, (T, U, ..).

Functions

pub fn foo(x: i32, y: i32) -> i32 {
    x + y
}

Control Flow

If

if x > 0 {
   ...
} else {
   ...
}

Loops

// For loop.
for i in iterator {
   ...
}

// While loop.
let i = 0
while i < 10 {
  ...
  i += 1;
}

Structs And Traits

// Defining structs.
pub struct Base {
    a: i32,
    b: i32,
    c: i32,
}

pub struct Derived1 {
    base: Base,
    d: i32,
}

pub struct Derived2 {
    base: Base,
    e: i32,
}

// Defining traits.
pub trait BaseTrait {
    fn a(&self) -> i32;
    fn b(&self) -> i32;
    fn c(&self) -> i32;
}

pub trait Derived1Trait : BaseTrait {
    fn d(&self) -> i32;
}

pub trait Derived2Trait : BaseTrait {
    fn e(&self) -> i32;
}

// Implementations.
impl BaseTrait for Derived1 {
    fn a(&self) -> i32 { self.base.a }
    fn b(&self) -> i32 { self.base.b }
    fn c(&self) -> i32 { self.base.c }
}

impl Derived1Trait for Derived1 {
    fn d(&self) -> i32 { self.d }
}

impl BaseTrait for Derived2 {
    fn a(&self) -> i32 { self.base.a }
    fn b(&self) -> i32 { self.base.b }
    fn c(&self) -> i32 { self.base.c }
}

impl Derived2Trait for Derived2 {
    fn e(&self) -> i32 { self.e }
}

Enums

enum IpAddrKind {
    V4,
    V6,
}

References

let data: DataType = DataType::new();

// Create a reference.
let data_ref: &DataType = &data;

// Create a mutable reference.
let mut data_mut_ref: &DataType = &data;

Smart Pointers

Smart pointers allow us to define data on heap instead of stack.

Box<T>

Define a single owner smart pointer.

let data: Box<DataType> = Box::new(DataType::new());

Rc<T>

Define a multi-owners smart pointer.

use std::rc::Rc;
let data: Rc<DataType> = Rc::new(DataType::new());

Ref<T> and RefCell<T>

use std::rc::Rc;
use std::cell::RefCell;

let data: Box<RefCell<DataType>> = Box::new(RefCell::new(DataType::new()));

// Get a reference.
let data_ref = data.borrow();

// Get an immutable reference.
let data_mut_ref = data.borrow_mut();

Common Data Structures

Vector<T>

let mut vec = Vec::new();
vec.push(1);
vec.push(2);

assert_eq!(vec.len(), 2);
assert_eq!(vec[0], 1);

assert_eq!(vec.pop(), Some(2));
assert_eq!(vec.len(), 1);

vec[0] = 7;
assert_eq!(vec[0], 7);

vec.extend([1, 2, 3]);

for x in &vec {
    println!("{x}");
}
assert_eq!(vec, [7, 1, 2, 3]);

HashMap<K, V>

use std::collections::HashMap;

// Type inference lets us omit an explicit type signature (which
// would be `HashMap<String, String>` in this example).
let mut book_reviews = HashMap::new();

// Review some books.
book_reviews.insert(
    "Adventures of Huckleberry Finn".to_string(),
    "My favorite book.".to_string(),
);
book_reviews.insert(
    "Grimms' Fairy Tales".to_string(),
    "Masterpiece.".to_string(),
);
book_reviews.insert(
    "Pride and Prejudice".to_string(),
    "Very enjoyable.".to_string(),
);
book_reviews.insert(
    "The Adventures of Sherlock Holmes".to_string(),
    "Eye lyked it alot.".to_string(),
);

// Check for a specific one.
// When collections store owned values (String), they can still be
// queried using references (&str).
if !book_reviews.contains_key("Les Misérables") {
    println!("We've got {} reviews, but Les Misérables ain't one.",
             book_reviews.len());
}

// oops, this review has a lot of spelling mistakes, let's delete it.
book_reviews.remove("The Adventures of Sherlock Holmes");

// Look up the values associated with some keys.
let to_find = ["Pride and Prejudice", "Alice's Adventure in Wonderland"];
for &book in &to_find {
    match book_reviews.get(book) {
        Some(review) => println!("{book}: {review}"),
        None => println!("{book} is unreviewed.")
    }
}

// Look up the value for a key (will panic if the key is not found).
println!("Review for Jane: {}", book_reviews["Pride and Prejudice"]);

// Iterate over everything.
for (book, review) in &book_reviews {
    println!("{book}: \"{review}\"");
}

Queue<T>

// Create a simple Queue
let mut q: Queue<isize> = queue![];

// Add some elements to it
q.add(1);
q.add(-2);
q.add(3);

// Check the Queue's size
q.size();  // 3

// Remove an element
q.remove();  // Ok(1)

// Check the Queue's size
q.size();  // 2

// Peek at the next element scheduled for removal
q.peek();  // Ok(-2)

// Confirm that the Queue size hasn't changed
q.size();  // 2

// Remove the remaining elements
q.remove();  // Ok(-2)
q.remove();  // Ok(3)

// Peek into an empty Queue
q.peek();  // Raises an error

// Attempt to remove an element from an empty Queue
q.remove();  // Raises an error
    ```