Week 3: Learning Rust

Hello! This week, Week 3, I will dive into my plan for learning Rust, how it panned out, and give some pointers and resources for those also learning Rust!

Baby Steps

Installing any new tool or language is my first step in learning it locally. That way, any examples I find can be modified in an environment that enables my curious mind to comment out lines, refactor code to see if it still works, or allows me to interact with a compiler/debugger sooner rather than later.

That being said, my first step was to install the Rust toolchain. As a Mac user, I am blessed to have Homebrew which enables easy access to a rust installer:

brew install rustup-init

This command installs Rust Up which is the pseudo-official way of installing the official toolchains published by the Rust team. While I will dig more into Rust tooling in Week 7, this installer has given you access to 3 important tools:

  • rustup: Lets you update, install, delete, and switch your default rust toolchains.
  • cargo: Rust's package manager and build tool. Think npm, but for Rust.
  • rustc: This is the rust compiler. You will learn to love/hate it. It's the equivalent of gcc to c.

Education

Since Rust is relatively new, the documentation for it is both a blessing and a curse. The blessing is that the Rust team has put together many "books" walking you through literally every part of the Rust language. The books are easy to read, straightforward, and instructive. However, it is also a curse because each chapter of the book is so descript and encompassing that even a tiny portion of a language, like variables, can take an hour to read and fully understand. For those with less time, there is also Rust By Example, an official book with a learn-by-example approach:

  • Many coded examples.
  • Great comments and annotations.
  • A handy crab that explains why things don't compile.

This book is where I found a lot of use in copying and modifying examples in my local environment, which helped me understand why something would or wouldn't compile.

Let's walk through a basic example written out in Rust By Example to see what parts of Rust are unique at first glance! While hello world is trivial in Rust, let's bump up our example to the classic FizzBuzz:

// Unlike C/C++, there's no restriction on the order of function definitions
fn main() {
    // We can use this function here, and define it somewhere later
    fizzbuzz_to(100);
}

// Function that returns a boolean value
fn is_divisible_by(lhs: u32, rhs: u32) -> bool {
    // Corner case, early return
    if rhs == 0 {
        return false;
    }

    // This is an expression, the `return` keyword is not necessary here
    lhs % rhs == 0
}

// Functions that "don't" return a value, actually return the unit type `()`
fn fizzbuzz(n: u32) -> () {
    if is_divisible_by(n, 15) {
        println!("fizzbuzz");
    } else if is_divisible_by(n, 3) {
        println!("fizz");
    } else if is_divisible_by(n, 5) {
        println!("buzz");
    } else {
        println!("{}", n);
    }
}

// When a function returns `()`, the return type can be omitted from the
// signature
fn fizzbuzz_to(n: u32) {
    for n in 1..=n {
        fizzbuzz(n);
    }
}

Source: https://doc.rust-lang.org/rust-by-example/fn.html

We can see that there is many similarities to other languages you may have learned! Pheww, what a relief that you do not have to relearn all your keywords, conditional syntax, and import mechanics!

Let’s dig into a few lines of code in particular:

fn is_divisible_by(lhs: u32, rhs: u32) -> bool { 
  • We can declare functions (in any order!) with the keyword fn (def in Python)
  • -> leads to the return type, in this case a boolean, bool (Same as in Typescript)
  • Variables and arguments have types. In this case, the variable lhs is a 32-bit unsigned integer, u32 .
if is_divisible_by(n, 15) {
  • Conditions without any explicit need for conditional operators (e.g. && or || ) do not need to be wrapped in parentheses, however the body of a conditional or function is delimited by curly braces (just like in C).
    for n in 1..=n {
  • For loops use the in syntax (just like Python), but have an interesting dot notation to identify ranges: .. for a non-inclusive suffix range, and ..= for an inclusive range (similar to Julia).

It is so interesting to see a new language like Rust build off of the best (IMO) parts of other languages that I already use and love. As a busy developer learning a new language for work or a student having to learn a new language for a class quickly, it’s reassuring to jump into the language and feel like you already have a large tool belt full of battle-hardened idioms that other languages pioneered decades ago. This is how I felt coming to Rust, and I quickly got up to speed on the functionality built into the base language.

There are more dimensions of Rust than I have room in this article to write but here are some other unique topics in Rust that a beginner might want to explore

  • Traits
  • Structs / Enums
  • References, borrows, and lifetimes
  • advanced control flow: match, collections, iterables
  • Basic data structures: str, String, vec, etc.

Resources

I found these resources super helpful in learning Rust. Sometimes I needed to have a topic explained in a different format or context to truly see the intricacy and necessity of some of Rust’s features.