Structs
A struct bundles related data under one name, the same job a class's fields do in Java or C# — Rust just separates the data (the struct) from the behavior (an impl block) instead of writing them together.
Defining and creating a struct
struct Account { owner: String, balance: f64, } fn main() { let account = Account { owner: String::from("Jamie"), balance: 100.0, }; println!("{}: {}", account.owner, account.balance); }
Jamie: 100
struct Account declares the shape: every account has an owner and a balance, with fixed types. Creating one fills in every field by name; dot syntax reads them back, same as most other languages on this site.
Methods live in an impl block
Behavior attaches to a struct through a separate impl (implementation) block, rather than being declared inside the struct itself:
struct Account { owner: String, balance: f64, } impl Account { fn deposit(&mut self, amount: f64) { self.balance += amount; println!("Deposited {}. New balance: {}", amount, self.balance); } } fn main() { let mut account = Account { owner: String::from("Jamie"), balance: 100.0 }; account.deposit(50.0); }
Deposited 50. New balance: 150
&mut self is a mutable borrow of the struct instance the method was called on — it's how deposit is allowed to change balance. Leaving off mut (just &self) gives a read-only method; leaving off self entirely defines an associated function instead, which is how constructors are conventionally written:
impl Account { fn new(owner: &str) -> Self { Self { owner: owner.to_string(), balance: 0.0 } } } fn main() { let account = Account::new("Sasha"); println!("{} starts with {}", account.owner, account.balance); }
Sasha starts with 0
new keyword and no built-in constructor — Account::new(...) above is just an ordinary associated function that happens to be named new by convention. Self (capital S) inside an impl block is shorthand for the type being implemented, so renaming Account later wouldn't require touching every constructor body.