Rust Fundamentals: Traits, Structs, Ownership & Iterators
Core Concepts
Structs vs Traits
- Struct = Data holder (like a class) - can be instantiated
- Trait = Behaviour contract (like an interface) - cannot be instantiated
- Structs hold data, traits define what you can do with data
Implementation Blocks (impl
)
impl StructName
= Inherent methods (struct’s own behavior)
impl TraitName for StructName
= Trait implementation (adding behavior contract)
- Multiple
impl
blocks allowed per struct
struct Player { name: String, score: i32 }
impl Player { fn new() -> Self { } } // inherent methods
impl Display for Player { fn fmt() { } } // trait implementation
Ownership & Borrowing
References & Dereferencing
&x
= Borrow (create reference, doesn’t own data)
*x
= Dereference (extract value from reference)
- References are just memory addresses, not data containers
Iterator Borrowing
.iter()
= borrows (&T
)
.into_iter()
= takes ownership (T
)
.iter_mut()
= mutable borrows (&mut T
)
Iterators
Functional Patterns
- Lazy by default - nothing happens until consuming method called
- Consuming methods:
collect()
, reduce()
, for_each()
, find()
- Transforming methods:
map()
, filter()
, enumerate()
Data Collection Patterns
- Tuples:
(String, i32)
- good for 2-3 simple fields like (make, year)
- Tuple structs:
struct Position(f64, f64)
- named tuples for coordinates
- Regular structs:
struct Car { make: String, year: i32 }
- best for complex data
#[derive(Debug, Clone)]
- auto-implement common traits
Error Handling
Core Types
Result<T, E>
= Success (Ok(T)
) or Error (Err(E)
)
Option<T>
= Has value (Some(T)
) or no value (None
)
Handling Patterns
unwrap()
= Extract value or panic (runtime crash) - avoid in production
?
operator = Propagate errors early return - standard for production
match
= Explicit pattern matching for all cases
unwrap_or()
= Provide default value if error/none
fn might_fail() -> Result<i32, String> {
let value = some_operation()?; // early return if error
Ok(value + 1)
}