Ownership and borrowing

AI-generated

fn length(value: &str) -> usize {
    value.len()
}

fn main() {
    let name = String::from("Ferris");
    println!("{} has {} bytes", name, length(&name));
}

Passing &name borrows the value, so main keeps ownership. Use &mut T for an exclusive mutable borrow; Rust permits either many immutable references or one mutable reference at a time.

Option and Result

AI-generated

fn first(items: &[String]) -> Option<&str> {
    items.first().map(String::as_str)
}

fn parse_port(raw: &str) -> Result<u16, std::num::ParseIntError> {
    raw.parse()
}

Option<T> represents a value that may be absent. Result<T, E> represents an operation that may fail. Prefer matching or the ? operator over unwrap() in code that must handle bad input gracefully.

Iterators

AI-generated

let even_squares: Vec<i32> = (1..=8)
    .filter(|n| n % 2 == 0)
    .map(|n| n * n)
    .collect();

Iterator adapters are lazy; collect, sum, and for_each are examples of consumers that drive the iterator.

Testing

AI-generated

fn add(a: i32, b: i32) -> i32 {
    a + b
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn adds_two_numbers() {
        assert_eq!(add(2, 3), 5);
    }
}

Run unit and integration tests with cargo test; use cargo clippy for common correctness and style lints and cargo fmt --check in CI.