Get a taste of Rust, it's like iron!

14/03/2023 • 7 min read

Rust is a fast, safe, and concurrent systems programming language that can be used for aaanything. And, it would probably be up amongst the best choices can be made.

Here is why Rust excites me:

  • Memory safety without garbage collection and manual memory management!
  • High-level ergonomics and low-level control (and it is FAST!)
  • Cross-platform compatibility
  • Excellent package/module management
  • It's popular and has proven itself

This post is going to give you a context of the world of Rust rather than teaching you directly. So, this is just a summary so that you don't get overwhelmed and/or get lost while reading the Rust book.

Here is a general comparison to other languages:

Memory safetyLow-level controlHigh-level ergonomicsExtra code required for compatibilityPackage managementSpeed (relative & shallow)Popularity
RustLowExcellentFastProven
CHighPoorFastEstablished
C++MediumPoorFastEstablished
Java (gc)LowGoodModerateEstablished
JavaScript (gc)LowExcellentSlowEstablished
Go (gc)LowExcellentFastProven

Concepts

Ownership and Borrowing: Think of it like a playground, where you have different kids playing with different toys. Ownership means who gets to play with the toy first and for how long. Borrowing means if someone else gets to play with the toy for a little bit without taking it away from the original player.

Lifetimes: Like the timer for how long the toy can be played with. They make sure that the toy is always returned to the original player before the timer runs out.

These ensure you write memory-safe code.

Concurrency: Rust has built-in tools for writing high-performance, multi-tasking programs.

Structs and impl's: Structs -> custom data types, and impl's are used to define methods for those data types. Like classes, but not quite! You won't have instances of impl's but structs.

Match: Pattern matching feature like switch but a bit better. You'll face with Result and Option frequently. That's where you are going to use match, directly on indirectly.

Unsafe code: Rust provides the ability to write unsafe code when necessary. This enables Rust to be interoperable with low-level languages. Yes, you can call a C function. Plus, other benefits...

Generics: Parameterized types that allow you to write code that can work with multiple data types. TypeScript viibes!

Modules and packages: Modules are used to organize code into separate and reusable components. And, Rust has a built-in package manager (and build system) called cargo like npm!

Error handling: Rust provides the Result type, and quite a lot, which makes it easy to handle errors in a way that is both type-safe and composable. It forces you to handle the possible errors. Try to remember all the problems you had because possible errors were ignored...

DALL·E 2023-03-11 16.18.30 - a person (sticking tongue out) about to lick a medium sized rusty crab made of iron.

Yes... Generated by DALL·E. [A person (sticking tongue out) about to lick a medium sized rusty crab made of iron.]

Tasting rust MIGHT be dangerous and harmful to health, and it is not recommended. Or you know, I'm just a text, can't stop you 🙄.

Syntax

  • let: Declare variable.
  • if: Control flow in a program based on conditions.
  • while: Repeat a block of code while a condition is true.
  • for: Loop over collections or a range of values.
let mut counter = 0; // mut means mutable variable
while counter < 5 {
    if number % 2 == 0 {
        println!("The counter {} is even.", counter);
    } else {
        println!("The counter {} is odd.", counter);
    }
    counter += 1;
}

for number in 0..5 {
    println!("The number is {}", number);
}
  • match: Perform pattern matching and control flow based on the value of an expression.
  • loop: Repeat a block of code indefinitely.
  • break: Break out of a loop.
  • continue: Skip to the next iteration of a loop.
let mut counter = 0;
loop {
    match counter {
        1 => println!("One"),
        3 | 4 | 5 => println!("Three, Four or Five"),
        6 => break,
        _ => println!("Something else"),
    }
    counter += 1;
}
  • fn: Define a function.
  • struct: Define a struct, a custom data type that can contain multiple fields.
  • impl: Define implementation blocks for types, traits, or other items. Matches by the name.
  • trait: Define traits, which are abstractions that define common behaviors for types.
  • type: Define type aliases or new types.
  • enum: Define an enumerated type, a type that has a finite set of named values.
trait Greet {
    fn greet(&self) -> String;
}

struct Person {
    name: String,
}

impl Greet for Person {
    fn greet(&self) -> String {
        format!("Hello, my name is {}", self.name)
    }
}

enum Result<T, E> { // <-- Generics!
    Ok(T),
    Err(E),
}

type R<T> = Result<T, String>;

fn main() {
    let p = Person { name: "John".to_owned() }; // <-- instantiate structs
    println!("{}", p.greet());

    let r: R<i32> = R::Ok(10);
    match r {
        R::Ok(value) => println!("Success: {}", value),
        R::Err(error) => println!("Error: {}", error),
    }
}
  • mod: Define a module, a named namespace that can contain functions, structs, and other items.
  • use: Bring names into scope and import them into the current namespace.
  • pub: Make an item public, allowing it to be accessible from outside the module.
  • extern: Declare an external Rust library to be linked to a project and for foreign function interfaces (FFI).
mod greeting {
    pub fn say_hello() {
        println!("Hello from the greeting module");
    }
}

extern crate ext_library; // crate also refers to the current project
mod my_module; // links my_module.rs

use my_module::hello; // use hello from my_module
use greeting::say_hello as foo; // as: alias

fn main() {
    foo();
    my_module();
    ext_library::bar();
}

The module system

Modules are Rust's way of organizing and grouping related code.

Files are seen as modules. src/my_file.rs becomes my_file module. And, src/my_directory/mod.rs becomes my_directory module. mod.rs is a special filename like index.js.

But the compiler doesn't directly look for them. You declare the module with mod, later the compiler looks for them.

These are not exactly like import's in JavaScript. If you create new files under a module (like my_directory/my_submod.rs), they will be submodules.

Crates are like smaller projects: Package > Crate > Module

Community Resources

...are the best kind of resources.

Sites:

Online Communities:

3, 2, 1... Start!

  1. Install Rust
  2. Configure your IDE: VSCode, IntelliJ IDEA, vim, or... try out the Online IDE
  3. Run cargo new!

Before you go, these 10 functions also could help you:

  • println!: output to the console.
  • format!: format string values.
  • unwrap: get the value of an Ok variant or panic if it is an Err.
  • expect: similar to unwrap, but it allows you to specify a custom error message.
  • vec!: a macro for creating a Vec (vector) with pre-populated data.
  • map: a method for transforming elements in a collection.
  • filter: a method for filtering elements in a collection.
  • sort_by: a method for sorting elements in a collection.
  • for_each: a method for executing an action on each element in a collection.
  • len: a method for getting the length of a collection.

Good luck!


I wrote this post before the earthquake on 6th of February in Turkey actually. Didn't feel like finalizing for a while.

𐰋

"Get a taste of Rust, it's like iron!", 14/03/2023, 16:50:00

#cheatsheet, #language, #rust