“the book”, trying some basic things and loosely following along with the examples. Although I’ve only gone through the first three chapters — stopping after the common programming concepts and leaving the idea of ownership for later — I’m still planning to write down what I found interesting about the language compared to the ones I use more often (mainly Python and Julia).
Nothing interesting will be written here for anyone familiar with Rust, but I’m growing fond of the idea behind “blogumentation” for self-documentation. In this case, writing things down that I found interesting will help me remember them:
;
Like multiple other languages, Rust uses the semicolon after statements. I wondered why this is so often the convention, and found a blog post by Nicole Tietz speculating why that is the case.
Using Cargo — which also initialises a new Git repository by default and creates the project structure when you begin a new project — seems like a great workflow.
“Cargo expects your source files to live inside the
src
directory. The top-level project directory is just for README files, license information, configuration files, and anything else not related to your code. Using Cargo helps you organise your projects. There’s a place for everything, and everything is in its place.”
In general, I think it’s helpful that it initialises and enforces this organisation. I tend to ignore conventions when quickly whipping something up in Python, which gets messy quickly.
Variables are immutable by default, but I was initially confused as to why you would allow shadowing for immutable variables. I did not immediately see any scenario where it would make sense to shadow an immutable variable. This will probably make more sense once I see some examples in practice. Another thing about shadowing that I found a bit weird is the example below:
let spaces = " ";let spaces = spaces.len();
“The first spaces variable is a string type and the second spaces variable is a number type. Shadowing thus spares us from having to come up with different names, such as
spaces_str
andspaces_num
; instead, we can reuse the simplerspaces
name.”
This feels like a fast way for things to get messy, shadowing the same variable in different scopes but changing the type (and thus the meaning) of the variable, but keeping the name. spaces_str
and spaces_num
don’t sound so bad to me, as the names at least convey meaning.
“Number literals can also use _ as a visual separator to make the number easier to read, such as 1_000, which will have the same value as if you had specified 1000.”
Through looking up other languages that provide a visual separator for integer literals, I stumbled upon this GitHub issue, which contains some interesting discussion on separators.
A lot of these might seem very standard, but as Python is my daily driver, it’s nice to try a language that has:
let truncated = -5 / 3; // Results in -1
let tup = (500, 6.4, 1);let (x, y, z) = tup;
let a = [3; 5]; // same as writing let a = [3, 3, 3, 3, 3];
fn main() { print_labeled_measurement(5, 'h');} fn print_labeled_measurement(value: i32, unit_label: char) { // println!("The measurement is: {value}{unit_label}");}
$ cargo run Compiling functions v0.1.0 (file:///projects/functions)error: expected expression, found `let` statement --> src/main.rs:2:14 |2 | let x = (let y = 6); | ^^^ | = note: only supported directly in conditions of `if` and `while` expressions
$ cargo run Compiling branches v0.1.0 (file:///projects/branches)error[E0308]: mismatched types --> src/main.rs:4:8 |4 | if number { | ^^^^^^ expected `bool`, found integer For more information about this error, try `rustc --explain E0308`.error: could not compile `branches` (bin "branches") due to 1 previous error
if
, but enforcing that the result of each arm must be of the same type:let number = if condition { 5 } else { 6 };
loop
keyword and loop labels (probably used sparingly as there are while
and for
keywords as well):fn main() { loop { println!("again!"); }}
Looking forward to learning more about Rust!