main.rsCourse
Rust
A typed name, then a struct with a method, then why a second name needs clone, a method that changes the struct, an enum, and a trait.
- name&strlatte
- centsi32450
- readybooltrue
6 lessons, in orderFree to read
Syllabus
Basics
The types, explained, then an object you can name and call.
-
01
Rust from zero: a name has a type
2 min read
A Rust name has a type. name is a string slice, cents is an i32, and ready is a bool. The program prints latte $4.50 ready.
fn main() { let name: &str = "latte"; let cents: i32 = 450; let ready: bool = true; let status = if ready { "ready" } else { "sold out" }; println!("{name} ${}.{:02} {status}", cents / 100, cents % 100); }latte $4.50 ready -
02
Rust from zero: a struct is the object
2 min read
A struct groups fields, and impl adds a method. Item holds a drink and a price in cents. label prints latte $4.50.
Builds on lesson 1.
struct Item { name: String, cents: i32, } impl Item { fn label(&self) -> String { format!("{} ${}.{:02}", self.name, self.cents / 100, self.cents % 100) } } fn main() { let latte = Item { name: String::from("latte"), cents: 450, }; println!("{}", latte.label()); }latte $4.50
Practice
A rule that prevents a bug, then a program that uses the object.
-
03
Assigning a String moves it. The old name cannot use it. clone keeps both. The program prints latte latte.
Builds on lessons 1 through 2.
fn main() { let a = String::from("latte"); let b = a.clone(); println!("{a} {b}"); }latte latte -
04
A method with &mut self changes the struct. add_tip adds 20 percent to a $4.50 bill, and the program prints $5.40.
Builds on lessons 1 through 3.
struct Bill { cents: i32, } impl Bill { fn add_tip(&mut self, percent: i32) { self.cents += self.cents * percent / 100; } } fn main() { let mut bill = Bill { cents: 450 }; bill.add_tip(20); println!("${}.{:02}", bill.cents / 100, bill.cents % 100); }$5.40
Further
One more idea, then a program that puts the pieces together.
-
05
Rust from zero: an enum names the cases
2 min read
An enum lists the shapes a value can have. Paid is Yes with the cents, or No. The program prints paid 450 and unpaid.
Builds on lessons 1 through 4.
enum Paid { Yes(i32), No, } fn read(a: Paid) -> String { match a { Paid::Yes(cents) => format!("paid {cents}"), Paid::No => "unpaid".to_string(), } } fn main() { println!("{}", read(Paid::Yes(450))); println!("{}", read(Paid::No)); }paid 450 unpaid -
06
Rust from zero: a trait is a method list
2 min read
A trait names the methods a function needs. Label asks for label. Item implements it. show prints latte $4.50.
Builds on lessons 1 through 5.
struct Item { name: String, cents: i32, } trait Label { fn label(&self) -> String; } impl Label for Item { fn label(&self) -> String { format!("{} ${}.{:02}", self.name, self.cents / 100, self.cents % 100) } } fn show(item: &impl Label) { println!("{}", item.label()); } fn main() { let latte = Item { name: String::from("latte"), cents: 450 }; show(&latte); }latte $4.50
Readings
Shorter pieces in the same language. Any order is fine once the lessons feel familiar.
-
The borrow checker: many readers or one writer
2 min
GoByte Skills #12: Rust lets you hold many shared references or one mutable one, never both. That single rule is why push on a borrowed Vec does not compile, and why two threads cannot write the same variable without a lock or an atomic.
-
Ownership: one owner, no garbage collector
2 min
GoByte Skills #11: Rust frees memory without a garbage collector because every value has exactly one owner. Move it and the old name is dead. When the owner's scope ends, the compiler has already written the drop call.
-
The ? operator: errors are values
3 min
GoByte Skills #10: The ? operator is a match you did not have to type. On Err it converts the error through From and returns early, so the error changes type on the way up and never leaves the signature. No exceptions, no unwinding.