Rust Language Basics
Rust can feel strict when coming from a dynamic language: conditions must be Boolean, bindings are immutable by default, and the compiler tracks how values are used. Those constraints make more program behavior visible before execution.
Bindings and Expressions
A binding created with let is immutable unless it is marked mut:
let width = 4;
let mut height = 3;
height = 5;
Shadowing creates a new binding with the same name. It differs from mutation because the new binding may have a different type while the earlier binding remains unchanged within its own scope.
Many Rust constructs are expressions. An if can therefore produce a value, and a function can return its final expression without return:
fn larger(a: i32, b: i32) -> i32 {
if a > b { a } else { b }
}
The absence of a trailing semicolon is significant here: adding one turns the expression into a statement whose value is ().
Data and Control Flow
Rust has scalar types such as integers, floating-point numbers, Boolean values, and Unicode scalar-value characters. Tuples group a fixed set of possibly different types; arrays contain a fixed number of values of one type. Vectors are used when the sequence must grow or shrink.
Control flow includes if, loop, while, for, and match. A match must cover every possible case, which makes it especially useful with enums:
match direction {
Direction::Left => turn_left(),
Direction::Right => turn_right(),
}
A loop can return a value through break, while for is the natural choice for consuming or borrowing values from an iterator.
Building Types
Structs give names to fields that belong together. Enums describe a value that may be one of several variants. Methods are defined in impl blocks, and associated functions without a self parameter are commonly used as constructors.
These language features interact with Rust ownership and borrowing, which determines whether an operation moves, reads, or mutates a value.