Rust cheatsheet examples part_2
Tags: rust, cheatsheet, tutorial
Published: 2024-02-20 13:38:46

Let's continue with more complex Rust concepts and structures.

## References, Ownership, and Borrowing

The stack is used for static memory allocation, while the heap is used for dynamic memory allocation, but both are stored in RAM, allowing for fast access by the CPU.
The stack is suitable only for data whose size is predetermined and constant. Conversely, data with variable or unknown sizes at compile time must be stored on the heap.

### Ownership rules

1. Each value in Rust has a variable that’s called its owner.
2. There can only be one owner at a time.
3. When the owner goes out of scope, the value will be dropped.

### Borrowing rules

1. At any given time, you can have either one mutable reference or any number of immutable references.
2. References must always be valid.

### Ownership and functions
```rust
fn main() {
    let num = 5;
    copy_value(num); // num is copied by value

    let text = String::from("Hello Rust!");
    take_ownership(text); // text is moved into the function

    let new_text = give_ownership(); // return value is moved into new_text

    let some_text = String::from("Rust");
    let final_text = take_and_give_back(some_text); // some_text is moved and then returned to final_text
}
```

### Creating references
```rust
let text1 = String::from("hello world!");
let ref1 = &text1; // immutable reference

let mut text2 = String::from("hello");
let ref2 = &mut text2; // mutable reference
ref2.push_str(" world!");
```

### Iterators
 Iterators are _lazy_, meaning they have no effect until you call methods that consume the iterator to use it up.

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

assert_eq!(v1_iter.next(), Some(&1)); 
assert_eq!(v1_iter.next(), Some(&2)); 
assert_eq!(v1_iter.next(), Some(&3)); 
assert_eq!(v1_iter.next(), None);
```
Note that `v1_iter` is mutable: calling the `next` method on an iterator changes internal state that the iterator uses to keep track of where it is in the sequence. In other words, this code _consumes_ the iterator. Each call to `next` eats up an item from the iterator. 

The values we get from the calls to `next` are immutable references to the values in the vector. The `iter` method produces an iterator over immutable references. If we want to create an iterator that takes ownership of `v1` and returns owned values, we can call `into_iter` instead of `iter`. Similarly, if we want to iterate over mutable references, we can call `iter_mut` instead of `iter`.

All iterators implement a trait named `Iterator` that is defined in the standard library. The definition of the trait looks like this:

```rust
// The `Iterator` trait only requires a method to be defined for the `next` element.
impl Iterator for Fibonacci {
    // `Item` type is used in the return type of the `next` method
    type Item = u32;

    // Here, we define the sequence using `.curr` and `.next`.
    // The return type is `Option<T>`:
    //     * When the `Iterator` is finished, `None` is returned.
    //     * Otherwise, the next value is wrapped in `Some` and returned.
    // We use Self::Item in the return type, so we can change
    // the type without having to update the function signatures.
    fn next(&mut self) -> Option<Self::Item> {
        let current = self.curr;

        self.curr = self.next;
        self.next = current + self.next;

        // Since there's no endpoint to a Fibonacci sequence, the `Iterator` 
        // will never return `None`, and `Some` is always returned.
        Some(current)
    }
}

// Returns a Fibonacci sequence generator
fn fibonacci() -> Fibonacci {
    Fibonacci { curr: 0, next: 1 }
}
```

### Copy, Move, and Clone
Simple types that implement the `Copy` trait are copied by value, meaning both the original and the copy can be used independently. Simple types often stored in the stack memory due to their fixed size and simplicity.
1. **All the integer types**, such as `i8`, `i16`, `i32`, `i64`, `i128`, `u8`, `u16`, `u32`, `u64`, `u128`.
2. **The floating point types**: `f32` and `f64`.
3. **The Boolean type**: `bool`, which can be either `true` or `false`.
4. **The character type**: `char`, representing a single Unicode scalar value.
5. **Tuples**, but only if they contain types that are also `Copy`. For example, `(i32, f64)` is `Copy`, but `(i32, String)` is not because `String` does not implement `Copy`.
6. **Arrays** with a fixed size that contain types that are `Copy`. For example, `[i32; 5]` is `Copy`, but `[String; 5]` is not because `String` does not implement `Copy`.
7. **Pointers**, such as raw pointers (`*const T`, `*mut T`) and function pointers (`fn`), but not references (`&T`, `&mut T`) or smart pointers like `Box<T>`.
It's important to note that if a type implements the `Drop` trait, it cannot implement the `Copy` trait. This is because the `Drop` trait requires custom logic to be executed when a value goes out of scope, which would conflict with the unrestricted bitwise copying behavior of `Copy` types.
```rust 
let num = 5; 
let copy_of_num = num; // `num` implements Copy, so it's copied, not moved
```

For types that do not implement `Copy`, such as `String`, assignment moves the value. After moving, the original variable cannot be used.
```rust
let text = String::from("Hello");
let moved_text = text; // `text` is moved to `moved_text`
// println!("{}", text); // This would cause an error because `text` is no longer valid
```

To explicitly clone the data, creating a separate instance that does not affect the original, use the `clone` method.
```rust
let text = String::from("Hello");
let cloned_text = text.clone(); // `text` is cloned, both `text` and `cloned_text` are valid
```

## Error Handling

#### Throw unrecoverable error
```rust
panic!("Critical error! Exiting!");
```
#### Option enum
```rust
fn find_user_id(username: &str) -> Option<u32> {
    if user_db.exists(username) {
        return Some(user_db.get_id(username))
    }
    None
}
```

#### Result enum
```rust
fn fetch_user(user_id: u32) -> Result<User, Error> {
    if is_user_logged_in(user_id) {
        return Ok(get_user_details(user_id))
    }
    Err(Error { message: "User not logged in" })
}
```
#### ? operator
The question mark operator (`?`) unwraps valid values or returns errornous values, propagating them to the calling function. It is a unary postfix operator that can only be applied to the types `Result<T, E>` and `Option<T>`.
```rust
fn calculate_salary(database: Database, user_id: i32) -> Option<u32> {
    Some(database.get_employee(user_id)?.get_position()?.salary)
}

fn establish_connection(database: Database) -> Result<Connection, Error> {
    let connection = database.find_instance()?.connect()?;
    Ok(connection)
}
```

## Threads
Rust provides a mechanism for spawning native OS threads via the `spawn` function, the argument of this function is a moving closure. Rust ensures safety and easy management of threads, adhering to its principles of memory safety and concurrency.

### Creating a Thread

You can create a new thread by calling `std::thread::spawn` and passing a closure containing the code you wish to run in the new thread.

```rust
use std::thread;

const THREADS_COUNT: u32 = 10;
let mut items = vec![];

for i in 0..THREADS_COUNT {
	// Spin up another thread
	item.push(thread::spawn(move || {
		println!("this is thread number {}", i);
	}));
}

for i in item {
	// Wait for the thread to finish. Returns a result.
	let _ = i.join();
}
```

### Sharing Data Between Threads

Rust's ownership rules extend to threads, ensuring safe data sharing. To share data between threads, you can use atomic types, mutexes, or channels.

#### Using Mutex for Safe Data Access
Mutex means `mutual exclusion`, which means "only one at a time". `Mutex` is safe, because it only lets one process change data at a time. To do this, it uses `.lock()`

```rust
use std::sync::{Arc,Mutex};
use std::thread;
use std::time::Duration;

struct JobStatus {
    jobs_completed: u32,
}

fn main() {
	// using an Arc to share memory among threads, and the data inside
	// the Arc is protected with a mutex.
    let status = Arc::new(Mutex::new(JobStatus { jobs_completed: 0 }));
    let mut handles = vec![];
    for _ in 0..10 {
        let status_shared = Arc::clone(&status);
        let handle = thread::spawn(move || {
            thread::sleep(Duration::from_millis(250));
            let mut jobs_count = status_shared.lock().unwrap();
            jobs_count.jobs_completed += 1;
        });
        handles.push(handle);
    }
    for handle in handles {
        handle.join().unwrap();
        println!("jobs completed {}", status.lock().unwrap().jobs_completed);
    }
}
// Output:
jobs completed 5  
jobs completed 5  
jobs completed 5  
jobs completed 7  
jobs completed 7  
jobs completed 7  
jobs completed 7  
jobs completed 9  
jobs completed 9  
jobs completed 10
```

#### Using Channels for Communication
Rust provides asynchronous `channels` for communication between threads. Channels allow a unidirectional flow of information between two end-points: the `Sender` and the `Receiver`.

```rust
use std::sync::mpsc;
use std::thread;

let (tx, rx) = mpsc::channel();

for i in 0..10 {
    let tx = tx.clone();
    thread::spawn(move || {
        let message = format!("Message {}", i);
        tx.send(message).unwrap();
    });
}

for _ in 0..10 {
    let received = rx.recv().unwrap();
    println!("Received: {}", received);
}
```

### Combinators

#### #map
```rust
let some_name = Some("Rusty".to_owned());
let name_length = some_name.map(|name| name.len());

let name_result: Result<String, Error> = Ok("Alex".to_owned());
let person_result: Result<Person, Error> = name_result.map(|name| Person { name });
```
#### #and_then

```rust
let numbers = Some(vec![1, 2, 3]);
let first_num = numbers.and_then(|nums| nums.into_iter().next());

let parse_result: Result<&'static str, _> = Ok("10");
let int_result = parse_result.and_then(|num_str| num_str.parse::<i32>());
```
### Generics, Traits, and Lifetimes
Generics used to create definitions for items like function signatures or structs, which we can then use with many different concrete data types.

```rust
struct Pair<T, V> {
    first: T,
    second: V,
}

impl<T, V> Pair<T, V> {
    fn mix<V2, T2>(self, other: Pair<V2, T2>) -> Pair<T, T2> {
        Pair {
            first: self.first,
            second: other.second,
        }
    }
}
```

#### Traits
A _trait_ defines functionality a particular type has and can share with other types. We can use traits to define shared behavior in an abstract way. We can use _trait bounds_ to specify that a generic type can be any type that has certain behavior (implements certain Trait)
```rust
trait Voice {
    fn create(name: &'static str) -> Self; // required implementation 
    fn speak(&self) -> &'static str { "Oho" } // default implementation
}

struct Cat { name: &'static str }

impl Cat {
    fn meow() { // ... }
}

impl Voice for Cat {
    fn create(name: &'static str) -> Cat {
        Cat { name }
    }

    fn speak(&self) -> &'static str {
        "meow"
    }
}
```

#### Trait bounds
The `impl Trait` syntax works for straightforward cases but is actually syntax sugar for a longer form known as a _trait bound_; it looks like this:
```rust
pub fn post<T: Summary>(item: &T) {
    println!("Musk broke his ketamine dose again {}", item.summarize());
}
```
functions with multiple generic type parameters can contain lots of trait bound information between the function’s name and its parameter list
```rust
fn some_function<T: Display + Clone, U: Clone + Debug>(t: &T, u: &U) -> i32 {...}
// Alternative using "where" keyword:
fn some_function<T, U>(t: &T, u: &U) -> i32
where
    T: Display + Clone,
    U: Clone + Debug,
{
```

#### impl trait

We can also use the `impl Trait` syntax in the return position to return a value of some type that implements a trait, as shown here:
```rust
fn returns_summarizable() -> impl Summary {
    Tweet {
        username: String::from("horse_ebooks"),
        content: String::from(
            "of course, as you probably already know, people",
        ),
        reply: false,
        retweet: false,
    }
}
```
By using `impl Summary` for the return type, we specify that the `returns_summarizable` function returns some type that implements the `Summary` trait without naming the concrete type. In this case, `returns_summarizable` returns a `Tweet`, but the code calling this function doesn’t need to know that.

The ability to specify a return type only by the trait it implements is especially useful in the context of closures and iterators

#### Trait objects
Dynamic dispatch through a mechanism called ‘trait objects’ - way to achieve polymorphism in Rust. 
A trait object can be obtained from a pointer to a concrete type that implements the trait by _casting_ it (e.g. `&x as &Foo`) or _coercing_ it (e.g. using `&x` as an argument to a function that takes `&Foo`).

These trait object coercions and casts also work for pointers like `&mut T` to `&mut Foo` and `Box<T>` to `Box<Foo>`
```rust
pub trait Draw { 
  fn draw(&self); 
}

pub struct Screen {
  pub components: Vec<Box<dyn Draw>>,
}

impl Screen {
    pub fn run(&self) {
        for component in self.components.iter() {
            component.draw();
        }
    }
}

struct Button {
    width: u32,
    height: u32,
    label: String,
}

impl Draw for Button {
    fn draw(&self) {
        // code to actually draw a button
    }
}
// --------
use gui::Draw;

struct SelectBox {
    width: u32,
    height: u32,
    options: Vec<String>,
}

impl Draw for SelectBox {
    fn draw(&self) {
        // code to actually draw a select box
    }
}
// -------

use gui::{Button, Screen};

fn main() {
    let screen = Screen {
        components: vec![
            Box::new(SelectBox {
                width: 75,
                height: 10,
                options: vec![
                    String::from("Yes"),
                    String::from("Maybe"),
                    String::from("No"),
                ],
            }),
            Box::new(Button {
                width: 50,
                height: 10,
                label: String::from("OK"),
            }),
        ],
    };

    screen.run();
}
```

#### Supertraits
When you define a trait, you can specify that it requires the functionality of another trait using the supertrait syntax. This means that in order for a type to implement the dependent trait, it must also implement the supertrait(s).

```rust
use std::fmt;
// `Log` is a trait that has a supertrait `fmt::Display` from the Rust standard library. The `fmt::Display` trait requires the implementing type to define how it will be formatted when displayed as a string

trait Log: fmt::Display { 
  fn log(&self) {
	let output = self.to_string();

    println!("Logging: {}", output);
  }
}
```

#### Operator overloading
Rust allows for a limited form of operator overloading. There are certain operators that are able to be overloaded. To support a particular operator between types, there’s a specific trait that you can implement, which then overloads the operator.
```rust
use std::ops::Add;

#[derive(Debug, Copy, Clone, PartialEq)]
struct Vector {
    x: i32,
    y: i32,
}

impl Add for Vector {
    type Output = Vector;

    fn add(self, other: Vector) -> Vector {
        Vector {
            x: self.x + other.x,
            y: self.y + other.y,
        }
    }
}

fn main() {
    let v1 = Vector { x: 1, y: 0 };
    let v2 = Vector { x: 2, y: 3 };

    let v3 = v1 + v2;

    println!("{:?}", v3);
}
```

### Lifetimes
Lifetimes ensure that references are valid as long as we need them to be, main goal of lifetimes is to prevent _dangling references_.
Most of the time, lifetimes are implicit and inferred, just like most of the time, types are inferred. We must only annotate types when multiple types are possible. In a similar way, we must annotate lifetimes when the lifetimes of references could be related in a few different ways. Rust requires us to annotate the relationships using generic lifetime parameters to ensure the actual references used at runtime will definitely be valid

#### Lifetimes in function signatures
```rust
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
	if x.len() > y.len() { 
	x
  } else { 
	y
  } 
}
```

#### Lifetimes in Struct Definitions
This example demonstrates how to associate the lifetime of the fields within the `Profile` struct with the lifetime `'a`, ensuring that the references to `name` and `email` are valid for the duration of the `Profile` instance's existence.

```rust
struct Profile<'a> { 
  email: &'a str,
  name: &'a str,
}

let user_name = "Alex"; 
let user_email = "alex@example.com"; 
let user_profile = Profile { name: user_name, email: user_email };
```

#### Static Lifetimes

A `'static` lifetime is the longest possible lifetime, and it can live for the entire duration of a program. It's typically used for string literals.
```rust
let static_str: &'static str = "Permanent text";
```
`static_str` is a reference to a string literal with a `'static` lifetime, meaning it's guaranteed to be valid for the entire program runtime.

### Functions, Function Pointers, and Closures

Functions in Rust can be defined as associated functions of structs or as standalone functions. Function pointers and closures provide flexibility for dynamic function usage and functional programming paradigms.

#### Associated functions and methods

Structs can have associated functions and methods that act on instances of the struct. 
```rust 
struct Point { x: i32, y: i32 } 

impl Point { 
  fn create(x: i32, y: i32) -> Point { 
    Point { x, y } 
  } 
  
  fn get_x(&self) -> i32 { self.x }
}
let point = Point::create(5, 10); 
point.get_x();
```

#### Function Pointers

Function pointers allow passing functions as arguments to other functions.
```rust
fn compute(val: i32, operation: fn(i32) -> i32) -> i32 {
    operation(val)
}

fn square(num: i32) -> i32 {
    num * num
}

let squared_value = compute(5, square);
```

#### Creating Closures

Closures are anonymous functions that can capture their environment.

```rust
let increment = |num: i32| -> i32 { num + 1 };
let incremented_value = increment(5);
```

#### Returning Closures

Closures can be returned from functions. The `impl` keyword is used to return a closure.
```rust
fn add(amount: i32) -> impl Fn(i32) -> i32 {
    move |num: i32| num + amount
}

let add_five = add(5);
let result = add_five(10); // result == 15

fn add_or_subtract(a: i32) -> Box<dyn Fn(i32) -> i32> {
  if a > 10 {  
    Box::new(move |b| b + a)
  } else {  
    Box::new(move |b| b - a)
  } 
}
let var1 = add_or_subtract(10); // -10
let var2 = var1(2); // -10 +2 = 8
```

#### Closure Traits

- `FnOnce`: consumes the variables it captures from enclosing scope.
- `FnMut`: mutably borrows values from its enclosing scope.
- `Fn`: immutably borrows values from its enclosing scope.
```rust
fn apply<F>(value: i32, mut func: F) -> i32
where
    F: FnMut(i32) -> i32,
{
    func(value)
}

let double = |x: i32| x * 2;
let doubled_value = apply(5, double);
```

#### Store Closure in Struct

You can store closures in structs by specifying the closure trait in the struct definition.
```rust
struct Calculator<T>
where
    T: Fn(i32) -> i32,
{
    calculation: T,
}

let add_one = |num: i32| num + 1;
let calculator = Calculator { calculation: add_one };
let calculated_value = (calculator.calculation)(5);
```

#### Function that Accepts Closure or Function Pointer
Functions can accept closures or function pointers as parameters, allowing for flexible argument types.
```rust
fn execute_twice<F>(mut func: F, arg: i32) -> i32
where
    F: FnMut(i32) -> i32,
{
    func(arg) + func(arg)
}

let add_two = |x: i32| x + 2;
let executed_value = execute_twice(add_two, 10);
```


#### Pointers
##### References
```rust
let value = 10; 
let reference_to_value = &value; // Immutable reference 
let mutable_reference_to_value = &mut value; // Mutable reference
```

#### Raw Pointers
Rust has a number of different smart pointer types in its standard library, but there are two types that are extra-special. Much of Rust’s safety comes from compile-time checks, but raw pointers don’t have such guarantees, and are [unsafe](https://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/html/book/first-edition/unsafe.html) to use.
`*const T` and `*mut T` are called ‘raw pointers’ in Rust. Sometimes, when writing certain kinds of libraries, you’ll need to get around Rust’s safety guarantees for some reason. In this case, you can use raw pointers to implement your library, while exposing a safe interface for your users. For example, `*` pointers are allowed to alias, allowing them to be used to write shared-ownership types, and even thread-safe shared memory types (the `Rc<T>` and `Arc<T>` types are both implemented entirely in Rust).

Here are some things to remember about raw pointers that are different than other pointer types. They:

- are not guaranteed to point to valid memory and are not even guaranteed to be non-NULL (unlike both `Box` and `&`);
- do not have any automatic clean-up, unlike `Box`, and so require manual resource management;
- are plain-old-data, that is, they don't move ownership, again unlike `Box`, hence the Rust compiler cannot protect against bugs like use-after-free;
- lack any form of lifetimes, unlike `&`, and so the compiler cannot reason about dangling pointers; and
- have no guarantees about aliasing or mutability other than mutation not being allowed directly through a `*const T`.

Raw pointers are useful for FFI: Rust’s `*const T` and `*mut T` are similar to C’s `const T*` and `T*`, respectively. Raw pointers (`*const T` and `*mut T`) can point to any memory location.

```rust
#![allow(unused_variables)]
fn main() {
	let x = 5;
	let raw = &x as *const i32;
	
	let mut y = 10;
	let raw_mut = &mut y as *mut i32;
}

// When you dereference a raw pointer, you’re taking responsibility that it’s not pointing somewhere that would be incorrect. As such, you need `unsafe`:

#![allow(unused_variables)]
fn main() {
	let x = 5;
	let raw = &x as *const i32;
	
	let points_at = unsafe { *raw };
	
	println!("raw points at {}", points_at);
}
```

### Smart Pointers
- Smart pointers are data structures that not only act like a pointer but also have additional metadata and capabilities. 
- Smart pointers _own_ the data they point to and are usually implemented using structs..
- Smart pointers implement the `Deref` and `Drop` traits. The `Deref` trait allows an instance of the smart pointer struct to behave like a reference so you can write your code to work with either references or smart pointers. The `Drop` trait allows you to customize the code that’s run when an instance of the smart pointer goes out of scope.

#### Box\<T\>
Use `Box<T>` to allocate values on the heap.
```rust
let boxed_data = Box::new(5);
```

#### Rc\<T\> - multiple ownership with reference counting
```rust
let shared_data = Rc::new(5); 
let clone_of_shared_data = Rc::clone(&shared_data);
```

#### Ref\<T\>, RefMut\<T\>, and RefCell\<T\> - enforce borrowing rules at runtime instead of compile time.

```rust
let a = 5;  
let x1 = RefCell::new(a);  
let x2 = x1.borrow();  // Ref - immutable borrow  
let x3 = x1.borrow_mut();  // RefMut - mutable borrow  
let x4 = r1.borrow_mut();  // RefMut - second mutable borrow 
```

##### Multiple owners of mutable data

```rust
let x = Rc::new(RefCell::new(5));
```

### Packages, Crates, and Modules

Rust's module system allows you to organize your code into packages, crates, and modules for better readability and reusability.

- Packages is cargo feature that lets you build, test, and share crates.
- Crates - A tree of modules that produces a library or executable.
- Modules and use - Let you control the organization, scope, and privacy of paths.
- Paths - A way of naming an item, such as a struct, function, or module.

##### Creating a Package

```ssh
$ cargo new my_project --bin # For a binary 
$ crate cargo new my_library --lib # For a library crate
```

#### Defining and using modules
```rust
mod sausage_factory {
	pub use self::meats::PORK_SAUSAGE as sausage;
	pub use self::meats::VEGGIE_SAUSAGE as veggie_sausage;
	
	mod meats {
		pub const PORK_SAUSAGE: &'static str = "Juicy pork sausage";
	
		pub fn make_sausage() {
		  get_secret_recipe();
			println!("sausage made with {} and secret ingredient!", PORK_SAUSAGE);
		  }
		}

		// private function so nobody outside of this module can use it
		fn get_secret_recipe() -> String {
		  String::from("Ginger")
		}
	}

	mod veggies {
		pub const VEGGIE_SAUSAGE: &'static str = "Delicious veggie sausage";
		...
	}
}

fn main() {
  sausage_factory::meats::make_sausage();
  println!("Today we serve {} and {}", sausage_factory::sausage, sausage_factory::veggie_sausage)
}

```
##### Import module and use with custom name:
```rust
// Import module and use with custom name:
use std::fmt::Result;  
use std::io::Result as IoResult;

// Re-exporting with pub use
mod outer_module {  
	pub mod inner_module {
		pub fn inner_public_function() {} 
	}
}  
pub use crate::outer_module::inner_module;
```