1.xChapter 1 summary and quiz
Nice work making it here. Chapter 1 covered a lot of ground; this page compresses it into a reference you can revisit, followed by the chapter quiz. (The quizzes at chapter ends are the ones most worth doing with the lessons closed.)
Quick review
A statement is the smallest instruction that performs an action, usually ending in ;. Statements live in functions, named bundles of statements, and every program starts at the function named main, whose body is the code between its braces. println!'s ! marks it as a macro: for now, a supercharged function (chapter 24 owns the details). Breaking the language's grammar gives a syntax error, caught at compile time.
A comment (// to end of line, /* */ for blocks, which nest in Rust) is a note for humans; the best ones explain why, because the code already says what. Comments also temporarily disable code ("commenting out").
Data is the information programs operate on; a single piece of it is a value. Values live in RAM while a program runs. A variable is a named storage place for a value; let defines one and initializes it with its first value. Every variable has a type, known to the compiler at compile time, usually via type inference.
Plain let variables are immutable; adding mut makes one mutable, allowing assignment (=, the assignment operator) to replace its value. Rust won't compile a read of an uninitialized variable: a value is required not at declaration, but before first use.
println! prints and ends the line; print! doesn't end it. Both fill {} placeholders from arguments (which can be expressions), {name} directly embeds a variable, {0}/{1} pick arguments by position, and escape sequences (\n, \t, \", \\, plus {{ for a literal brace) write the unwritable.
Input arrives via read_line, which appends the user's line, Enter included, to a String; .trim() strips the edges. Standard input is the stream the user types into. The &mut and .expect(...) in the recipe are IOUs, redeemable in lessons 9.2 and 12.2.
Compiler errors have an anatomy: headline with error code, location, spans with carets and labels, then help: (the fix) and note: (the rule). rustc --explain E0308 prints the long-form article. Always read the first error first.
An identifier names something; it can't start with a digit, contain spaces, or be a keyword. Variables and functions use snake_case, and the compiler itself reminds you. Whitespace is mostly ignored outside strings and word boundaries; cargo fmt makes formatting a solved problem.
A literal is a value written directly in code (underscores like 1_000_000 are legal seasoning). Operators combine operands into new values; arity counts the operands (unary, binary); Rust has no ++/-- (write += 1).
And the big one: an expression is code that produces a value (evaluating it yields the value); a statement performs an action instead. An expression plus ; is an expression statement, its value discarded, which makes the semicolon Rust's discard marker. Side-effect expressions produce the unit type (). A block { ... } is itself an expression whose value is its final, semicolon-less tail expression, making Rust an expression-oriented language. That idea reappears in this course roughly forever.
Quiz time
Question #1
How many times can a variable be initialized? How many times can it be assigned to, and what does that require?
Show solution
Initialized exactly once (its first value, whether at the let or later-but-before-use). Assigned any number of times after that, but only if it was declared let mut.
Question #2
In one sentence each: what does a semicolon do to an expression, and what happens when a block's final line keeps its semicolon?
Show solution
A semicolon turns an expression into an expression statement, discarding its value. If a block's final line ends in a semicolon, the block has no tail expression and evaluates to (), which is usually not what the surrounding code wanted.
Question #3
Write a complete program that asks the user for two whole numbers, then prints their sum and their difference, exactly like this (user input shown as typed):
Enter a whole number:
6
Enter another whole number:
4
6 + 4 is 10
6 - 4 is 2Show solution
use std::io;
fn main() {
println!("Enter a whole number:");
let mut first = String::new();
io::stdin()
.read_line(&mut first)
.expect("failed to read input");
let x: i32 = first.trim().parse().expect("that wasn't a whole number");
println!("Enter another whole number:");
let mut second = String::new();
io::stdin()
.read_line(&mut second)
.expect("failed to read input");
let y: i32 = second.trim().parse().expect("that wasn't a whole number");
println!("{} + {} is {}", x, y, x + y);
println!("{} - {} is {}", x, y, x - y);
}
Points to check against your own version: each input gets its own fresh String (remember, read_line appends), each is trimmed before parsing, and the arithmetic lives as expressions right in the output statements, per lesson 1.12's reasoning.
If you typed this from a blank file and it ran: you're no longer reading about programming. You're doing it.
Next up, chapter 2, where programs stop being one long main and start growing parts: functions, the unit all larger structure is built from. (You may notice the repeated input-reading code in Question 3 begging to become one. Noticing that is chapter 2.)