Getting Started with Rust Using Rustlings — Part 1: Variables

Jesse Verbruggen
7 min readFeb 13, 2023
Rustlings Part 1: Variables

I recently caught up with an old friend who works as a Low-Level Software Engineer. He mainly uses C++. We got talking about Rust, as I had tried it out before. I explained the great toolchain built around Rust that allows for faster program delivery. He was interested but didn’t know where to begin, like me.

If you’re also keen on learning Rust, I invite you to join me on my journey. I’ll start with the basics of Rust, including installing the toolchain and, in the end, rewriting some coding problems I previously tackled. We’ll also compare the performance of the two with profiling tools.

Installing the rust toolchain

Let’s start by installing Rust and the different tools shipped with it. If you’re on Mac, you can follow along with the code blocks here.

We can use rustup to install all the different tools for installing Rust. Run the following command to run the installer in your CLI.

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

The default installation will put all your tools in ~/.cargo/bin . To add them to your path, you can source ~/.cargo/env . I’m using zsh, so I’ll add this command to my ~/.zshrc to have Rust available in my CLI.

# Append the command to ~/.zshrc
echo 'source ~/.cargo/env' >> ~/.zshrc

To test your installation and path, run the following command to check the version of cargo, which can be used to initialize, build and test your Rust packages and much more.

cargo --version

Getting started with Rustlings

One of the recommended options for learning Rust is rustlings. Check out its repository on Github if you’re on another platform.

If you’re following along on Mac, you can get started by running the following command, which will install rustlings to get you started. This will create a folder in the current directory called rustlings, so be sure to switch to whatever location you want to use to keep things organized.

curl -L https://raw.githubusercontent.com/rust-lang/rustlings/main/install.sh | bash

Now you can run cd rustlings to be transported straight to the folder containing the exercises at ./exercises . These are ordered in the Readme following the Book on Rust, so let’s do the intro, follow the recommended route, and start learning Rust.

> cat exercises/README.md 
# Exercise to Book Chapter mapping

| Exercise | Book Chapter |
| ---------------------- | ------------------- |
| variables | §3.1 |
| functions | §3.3 |
| if | §3.5 |
| primitive_types | §3.2, §4.3 |
| vecs | §8.1 |
| move_semantics | §4.1-2 |
| structs | §5.1, §5.3 |
| enums | §6, §18.3 |
| strings | §8.2 |
| modules | §7 |
| hashmaps | §8.3 |
| options | §10.1 |
| error_handling | §9 |
| generics | §10 |
| traits | §10.2 |
| tests | §11.1 |
| lifetimes | §10.3 |
| iterators | §13.2-4 |
| threads | §16.1-3 |
| smart_pointers | §15, §16.3 |
| macros | §19.6 |
| clippy | §21.4 |
| conversions | n/a |

Intro to Rustlings: Hello World!

Open the folder in your favourite editor. In my case, this is Visual Studio Code, which you can easily open just by running code . from the CLI if you have this configured for your path.

Now, from your CLI in the rustlings folder, run rustlings watch . This will point you to the first exercise, Hello World!

The exercise, located at exercises/intro/intro2.rs requires you to print Hello World! . This contains the following code.

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

Let’s change this code to the following to solve this exercise.

fn main() {
println!("Hello World!");
}

Now, your CLI, running rustlings watch , will indicate that the exercise is solved. To head on to the next exercise, remove the code comment at the top of the files, intro1.rs and intro2.rs, // I AM NOT DONE to move on to the next exercise, variables, which I cover in this article.

Exercise: Variables in Rust

The first exercise is about using variables in Rust and learning the syntax to create immutable and mutable variables.

Rust is a strongly typed language, with its variables being immutable by default. This means that when you create a variable in your code on assignment, it will be of the type assigned to it, and it cannot be changed unless you make it a mutable variable.

variables1.rs

fn main() {
x = 5;
println!("x has the value {}", x);
}

The first exercise has a syntax error for the Rust compiler. The compiler expects you to initialize a variable with the keyword let or const .

As we are not reassigning this variable later in the code, let’s try using a const for this. Defining a constant in Rust has two requirements. Firstly you need to use the keyword const then you can use whatever name you want to use for your variable, and you must specify a type with : type. In this case, it will look like this.

fn main() {
const x : i32 = 5;
println!("x has the value {}", x);
}

This will assign 5 as a 32-bit integer to x solve the first exercise. Remove // I AM NOT DONE it from the top of the exercise file. This will need to be done for each exercise. To keep this article concise, I will refrain from repeating this from this point on.

variable2.rs

fn main() {
let x;
if x == 10 {
println!("x is ten!");
} else {
println!("x is not ten!");
}
}

The following exercise isn’t working because the compiler cannot determine what type is inferred in x . To fix this, we can initialize x with a value.

Let’s initialize x to hold the value of 10.

fn main() {
let x = 10;
if x == 10 {
println!("x is ten!");
} else {
println!("x is not ten!");
}
}

This code solved our exercise, and there was no need to specify a type as we had to do in the previous exercise because, this time, we didn’t use a const.

variables3.rs

fn main() {
let x: i32;
println!("Number {}", x);
}

In this scenario, x is left uninitialized. In contrast to Go and some other programming languages, this does not initialize the variable with 0 . Therefore we must specify a value ourselves. This is because Rust is an explicit programming language with the goal of writing more understandable code. Let’s initialize this value to zero to solve our problem.

fn main() {
let x: i32 = 0;
println!("Number {}", x);
}

In this scenario, we used a specified type for let. This option makes the code readable in more complex applications.

variables4.rs

fn main() {
let x = 3;
println!("Number {}", x);
x = 5; // don't change this line
println!("Number {}", x);
}

Now, if you’re coming from pretty much any high-level programming language, like Java, Javascript, C# or Python, you’re probably wondering why this code does not compile. In Rust, whenever you want a variable to be mutable and change the value it contains, you need to specify it with the mut keyword. Adding this will make the code look like this.

fn main() {
let mut x = 3;
println!("Number {}", x);
x = 5; // don't change this line
println!("Number {}", x);
}

The mut keyword tells the compiler that this value will be reassigned later and solve the problem.

variables5.rs

fn main() {
let number = "T-H-R-E-E"; // don't change this line
println!("Spell a Number : {}", number);
number = 3; // don't rename this variable
println!("Number plus two is : {}", number + 2);
}

This problem might seem a bit more tricky as we are currently reusing a variable that holds a string and we try to put an integer into it. One of the features of Rust is that you can shadow variables and declare them within the same scope.

This is what that result looks like for this exercise.

fn main() {
let number = "T-H-R-E-E"; // don't change this line
println!("Spell a Number : {}", number);
let number = 3; // don't rename this variable
println!("Number plus two is : {}", number + 2);
}

This goes against best practices that I know, but this can be useful at times, although even then, I suggest renaming your variables to make sense in the same context. A situation in which this makes sense to me is if, within the same function, you need to make multiple requests to APIs and want to reuse response to hold the result.

variables6.rs

const NUMBER = 3;
fn main() {
println!("Number {}", NUMBER);
}

The final exercise shows us a constant value assignment. This assignment requires a type, as we did in the first solution. So let’s add a type and see if that works.

const NUMBER : i32 = 3;
fn main() {
println!("Number {}", NUMBER);
}

That worked! Alright, that’s all the exercises I will go over right now. I hope you enjoyed following along with me. As I complete the exercises, feel free to join me to start your journey into Rust. The next part about Functions in Rust is out now.

If I helped you learn more about Rust or you found this interesting, please clap 👏 and share this article to help more people find these articles.

Let’s help each other learn and grow! Peace out✌️

--

--