I was inspired to start learning Rust a few days ago after watching How to Learn Rust by No Boilerplate. Rust is a language I’ve been interested for awhile now, both because of it has some novel approaches I haven’t seen in other langs, and because it’s closer to the metal (and more efficient) then the JS and C# I am used too. I’ve worked with C++ some in the past, but I found it to be cumbersome at times. I am excited to try Rust’s more functional approach, as well as it’s memory safe features.
I am going to try to roughly follow No Boilerplate’s plan, with the additional of some projects. In general:
I plan on also adding some additional projects, before or during the above, including:
Over the last few days I’ve read the first half of the book, up through chapter 11. From hearing some about Rust before hand, I was expecting this to be confusing, so far though it reminds me a lot of TypeScript. The only feature that is going to take some getting used to is ownership.
Ownership is an interesting feature of Rust that helps make sure memory usage is safe; that there are no leaks or invalid references, two serious possibilities in C++. In short, the function that created a variable “owns” it, and ownership is passed on if the variable is passed to another function(or struct). Once ownership is passed the original function can no longer use the variable. Note ownership does not apply to scaler values. Example:
fn main() {
let a = String::from("foo");
// Pass `a` to `print`, thereby passing the ownership
print(a);
// Now `a` is no longer valid in `main`, since `main` does not own it
// If we try to print again..
print(a);
// We would get a compiler error
// `error[E0382]: use of moved value: `a``
}
fn print(a_string: String) {
println!("{a_string}");
}
If we still need a variable after passing ownership we must:
Ownership can take a minute to get used too, but once you do it is pretty natural to keep track of. To learn more checkout chapter 4 of the book.
Rust doesn’t have classes like OOP languages, instead it has structs and enums. These remind me of a mix of classes and interfaces/types in TypeScript. You can use them to define new types, like so:
struct Foo {
bar: u64,
}
Which could then get used like:
let a = Foo { bar: 1 };
println!("{}", a.bar); // prints 1
Additional, you can add methods to structs by adding an impl:
impl Foo {
fn print(&self) {
println!("{}", self.bar);
}
}
Called like
a.print(); // prints 1
Note that there is no way (without abusing macros at least) to do inheritance with structs. Inheritance can add a lot of unneeded complexity, instead composition is preferred.
In my next post, I will take a break from the book to mess around with Oort.