In this episode I aim to learn some Rust concepts beyond Hello World, using the book "The Rust Programming Language" as a guide.
I'm doing a series of 25 minute sessions where I try to get familiar with the Rust programming language. The blogposts in these series are the notes I took of the lessons learned along the way.
Warning to the reader: As always in this series, these are notes I take as I'm learning. They reflect my current understanding and may be incorrect!
Rust Learning Resources
For my first introduction I went to the book The Rust Programming Language.
The second edition of this book, completely rewritten, is available online (and soon in print).
Guessing Game Tutorial
From the book: I will follow this and take notes of interesting things.
Creating a new Project
You make an empty project using cargo:
cargo new guessing_game --bin
It's a git repo by default.
"guessing_game" is the name of the project.
Instantiating an object from a class looks like this:
let mut guess = String::new();
To me, it looks like this line is "newing up a String": it creates a new instance of the string.
We learn in the book that the
new method is a method on the class level. Which in some languages (like C#) is called a static method. In Rust it's called an associated function.
It seems the
new method isn't present in every class. And it could also be called something else.
new in this case is a convention.
mut is optional and not there by default. This means a "variable" can be assigned a value only once. You can not change the value afterwards.
In the guessing game, the variable must be mutable because it gets modified by
Error changing an immutable variable
If the string isn't made mutable using the
mut keyword, the following compile-time error occurs when passing it to a function expecting a mutable variable:
error[E0596]: cannot borrow immutable local variable `guess` as mutable --> src\main.rs:10:32 | 8 | let guess = String::new(); | ----- consider changing this to `mut guess` 9 | 10 | io::stdin().read_line(&mut guess) | ^^^^^ cannot borrow mutably
It talks about "borrowing". I've heard about scope and ownership in Rust and expect to learn more soon.
If I remove the
mut in the call to
read_line itself, I get the following error:
error[E0308]: mismatched types --> src\main.rs:10:27 | 10 | io::stdin().read_line(guess) | ^^^^^ | | | expected mutable reference, found struct `std::string::String` | help: consider mutably borrowing here: `&mut guess` | = note: expected type `&mut std::string::String` found type `std::string::String`
From this, we learn "&mut" means doing "mutably borrowing".
If I use
io::stdin().read_line(&guess) the following error appears:
error[E0308]: mismatched types --> src\main.rs:10:27 | 10 | io::stdin().read_line(&guess) | ^^^^^^ types differ in mutability | = note: expected type `&mut std::string::String` found type `&std::string::String`
mut on the variable declaration is not enough for Rust to know the references is mutable. If I remove
mut in the variable declaration, the above error is still the same. In other words: even if your variable is locally declared mutable, a reference to it isn't necessarily mutable.
println! is not a function but a macro. Which means, I think, the compiler translates it to some other code before compilation.
On the top of the file we use
use std::io; to import the io methods of the standard library.
Interestingly, when calling the methods from this library, we can do it like this:
io::stdin().read_line. I'm not sure why the
io:: needs to be repeated. Coming from C# I'm used to the following:
using System; ... Console.WriteLine("..."); // With 'using System;' is present System.Console.WriteLine("..."); // Without 'using System;'
io::stdin and a
use on top, it was also possible to write
std::io::stdin().read_line. Much like the
System.Console.WriteLine("..."); line in the above C# example.
What if I just to
error[E0254]: the name `std` is defined multiple times --> src\main.rs:1:5 | 1 | use std; | ^^^ `std` reimported here | = note: `std` must be defined only once in the type namespace of this module help: You can use `as` to change the binding name of the import | 1 | use std as other_std; | ^^^^^^^^^^^^^^^^
That was the 25 minutes today. I explored a few things in the example code from the book. I haven't made anything useful yet, but I got introduced to a couple of concepts:
- What Mutably Borrowing looks like (a reference declared with
- Macros exist
- What "includes" look like
- That a static method is called an associated method
- That classes declare an associated
Newmethod, but are not forced to do this (at least that is what I understood)
Can't wait to get the game working in the next 25 minutes.