Variables and Mutability in Rust

Pascal Precht
InstructorPascal Precht

Share this video with your friends

Send Tweet
Published 3 years ago
Updated 2 years ago

In this lesson we'll learn how to initialise variables in Rust and how to make them mutable using the mut keyword so they can be changed throughout the program.

Pascal Precht: [00:00] Variables in Rust are created using the let keyword. Let's create a variable name using let name = Pascal. To output this variable, we can use the println!() function. However, println!() takes a string as a parameter, but since name is not a string but a variable, we have to use the placeholder syntax, which is using curly braces. Then we can pass name as a second argument to this function.

[00:30] What Rust will then do is it will take this first argument, name, and replace it with this placeholder. When we save this program and then run the program using cargo run, we'll see that it outputs the name.

[00:44] One thing to note about variables is that they're immutable by default. What this means is that if we try to overwrite this variable with another value and then output it again, we'll see that once we run the program that Rust will complain it cannot assign a value twice to an immutable variable.

[01:07] It even tells us that the first assignment has happened to name in the second line of our program. It also tells us that we need to make the binding mutable using the mute keyword. If we change the variable to a mutable variable using the mute keywords and we run the program again, we'll see that it's successfully compiled without any problems.

[01:32] You might think that it's a bit of a hassle to define every variable as immutable if it's needed, but it turns out that it's a very powerful feature in Rust because just by looking at the code, you know when a variable is being changed by the program or not.

J. Matthew
J. Matthew
~ 3 years ago

The immutable-by-default feature would make my buddy so happy...

println!("{}", name);

I'm baffled by the above placeholder syntax, though. It seems like an odd way to interpolate variables into strings. Compared with JavaScript's classic string concatenation "Hello, " + name + "!" or as an ES6 template literal Hello, ${name}!, this seems more roundabout and harder to read. Why does Rust do it this way?

J. Matthew
J. Matthew
~ 3 years ago

Also, a quick transcript note: I noticed the last code section has let mutname = "Pascal"; rather than let mut name = "Pascal";.

Pascal Precht
Pascal Prechtinstructor
~ 3 years ago

Compared with JavaScript's classic string concatenation "Hello, " + name + "!" or as an ES6 template literal Hello, ${name}!, this seems more roundabout and harder to read. Why does Rust do it this way?

Hey Matthew,

that is a very interesting question. So first of all, I'm not a Rust compiler expert, so what I'm saying now might not be the actual reason, possibly only one of the reasons:

It turns out that println!() macro takes advantage of Rust's format!() macro: https://doc.rust-lang.org/std/macro.format.html

The format macro actually supports different types of formatters and placeholders. The lesson only covers the basic one ({}) but you might for example end up using the debug placeholder ({:?}) or even the pretty printed debug placeholder ({:#?}).

^ This alone already make "simple" string concatenation impossible. On top of that, it seems the compiler needs the first argument to be a string literal and anything that needs interpolation, as additional arguments so it can perform validity checks at compile time.

From the official docs (https://doc.rust-lang.org/std/fmt/):

From these, you can see that the first argument is a format string. It is required by the compiler for this to be a string literal; it cannot be a variable passed in (in order to perform validity checking). The compiler will then parse the format string and determine if the list of arguments provided is suitable to pass to this format string.

Notice that this is very similar to sprintf() fprintf() and printf(), functions in other languages.

Hope this makes a bit of sense.

J. Matthew
J. Matthew
~ 3 years ago

^ This alone already make "simple" string concatenation impossible. On top of that, it seems the compiler needs the first argument to be a string literal and anything that needs interpolation, as additional arguments so it can perform validity checks at compile time.

Ah, that does make sense (the general concepts I get, at any rate). That behavior seems in line with Rust's focus on catching as many possible issues as possible at compile time. So in this case sacrificing some legibility and convenience for the sake of code integrity. I can get behind that. Thanks for the explanation!

Pascal Precht
Pascal Prechtinstructor
~ 3 years ago

Nice! Happy I could help :)