๐Ÿฆ€ Functional Rust
๐ŸŽฌ How Rust Iterators Work Lazy evaluation, chaining, collect(), and zero-cost abstractions.
๐Ÿ“ Text version (for readers / accessibility)

โ€ข Iterators are lazy โ€” .map(), .filter(), .take() build a chain but do no work until consumed

โ€ข .collect() triggers evaluation, transforming the chain into a Vec, HashMap, or other collection

โ€ข Zero-cost abstraction: iterator chains compile to the same machine code as hand-written loops

โ€ข .iter() borrows, .into_iter() consumes, .iter_mut() borrows mutably

โ€ข Chaining replaces nested loops with a readable, composable pipeline

084: From and Into Traits

Difficulty: Intermediate Category: Traits Concept: Type conversions with `From`/`Into` traits Key Insight: Implement `From` and get `Into` for free. This is Rust's idiomatic conversion pattern โ€” no explicit cast needed.
// 084: From and Into Traits

// Approach 1: Temperature conversion
#[derive(Debug, Clone, Copy)]
struct Celsius(f64);

#[derive(Debug, Clone, Copy)]
struct Fahrenheit(f64);

impl From<Celsius> for Fahrenheit {
    fn from(c: Celsius) -> Self { Fahrenheit(c.0 * 9.0 / 5.0 + 32.0) }
}

impl From<Fahrenheit> for Celsius {
    fn from(f: Fahrenheit) -> Self { Celsius((f.0 - 32.0) * 5.0 / 9.0) }
}

// Approach 2: Enum from string (TryFrom)
#[derive(Debug, PartialEq)]
enum Color { Red, Green, Blue }

impl TryFrom<&str> for Color {
    type Error = String;
    fn try_from(s: &str) -> Result<Self, Self::Error> {
        match s {
            "red" => Ok(Color::Red),
            "green" => Ok(Color::Green),
            "blue" => Ok(Color::Blue),
            _ => Err(format!("Unknown color: {}", s)),
        }
    }
}

impl From<Color> for &str {
    fn from(c: Color) -> Self {
        match c { Color::Red => "red", Color::Green => "green", Color::Blue => "blue" }
    }
}

// Approach 3: From for complex types
struct RawUser { name: String, age: String, email: String }

#[derive(Debug, PartialEq)]
struct User { name: String, age: u32, email: String }

impl TryFrom<RawUser> for User {
    type Error = String;
    fn try_from(raw: RawUser) -> Result<Self, Self::Error> {
        let age = raw.age.parse().map_err(|_| "Invalid age".to_string())?;
        Ok(User { name: raw.name, age, email: raw.email })
    }
}

fn main() {
    let boiling: Fahrenheit = Celsius(100.0).into();
    println!("100C = {:.1}F", boiling.0);

    let freezing: Celsius = Fahrenheit(32.0).into();
    println!("32F = {:.1}C", freezing.0);

    let color: Result<Color, _> = Color::try_from("red");
    println!("color: {:?}", color);
}

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

    #[test]
    fn test_celsius_to_fahrenheit() {
        let f: Fahrenheit = Celsius(100.0).into();
        assert!((f.0 - 212.0).abs() < 0.001);
    }

    #[test]
    fn test_fahrenheit_to_celsius() {
        let c: Celsius = Fahrenheit(32.0).into();
        assert!(c.0.abs() < 0.001);
    }

    #[test]
    fn test_color_try_from() {
        assert_eq!(Color::try_from("red"), Ok(Color::Red));
        assert!(Color::try_from("purple").is_err());
    }

    #[test]
    fn test_user_try_from() {
        let raw = RawUser { name: "Alice".into(), age: "30".into(), email: "a@b.com".into() };
        let user = User::try_from(raw).unwrap();
        assert_eq!(user.age, 30);
    }

    #[test]
    fn test_user_invalid() {
        let raw = RawUser { name: "Bob".into(), age: "xyz".into(), email: "b@c.com".into() };
        assert!(User::try_from(raw).is_err());
    }
}
(* 084: From/Into โ€” OCaml conversion functions *)

(* Approach 1: Simple conversions *)
type celsius = Celsius of float
type fahrenheit = Fahrenheit of float

let fahrenheit_of_celsius (Celsius c) = Fahrenheit (c *. 9.0 /. 5.0 +. 32.0)
let celsius_of_fahrenheit (Fahrenheit f) = Celsius ((f -. 32.0) *. 5.0 /. 9.0)

(* Approach 2: String conversions *)
type color = Red | Green | Blue

let color_of_string = function
  | "red" -> Ok Red
  | "green" -> Ok Green
  | "blue" -> Ok Blue
  | s -> Error (Printf.sprintf "Unknown color: %s" s)

let string_of_color = function
  | Red -> "red"
  | Green -> "green"
  | Blue -> "blue"

(* Approach 3: Complex record conversion *)
type raw_user = { raw_name: string; raw_age: string; raw_email: string }
type user = { name: string; age: int; email: string }

let user_of_raw raw =
  match int_of_string_opt raw.raw_age with
  | None -> Error "Invalid age"
  | Some age -> Ok { name = raw.raw_name; age; email = raw.raw_email }

(* Tests *)
let () =
  let (Fahrenheit f) = fahrenheit_of_celsius (Celsius 100.0) in
  assert (abs_float (f -. 212.0) < 0.001);
  let (Celsius c) = celsius_of_fahrenheit (Fahrenheit 32.0) in
  assert (abs_float c < 0.001);
  assert (color_of_string "red" = Ok Red);
  assert (Result.is_error (color_of_string "purple"));
  assert (string_of_color Blue = "blue");
  let raw = { raw_name = "Alice"; raw_age = "30"; raw_email = "a@b.com" } in
  assert (user_of_raw raw = Ok { name = "Alice"; age = 30; email = "a@b.com" });
  let bad = { raw_name = "Bob"; raw_age = "xyz"; raw_email = "b@c.com" } in
  assert (Result.is_error (user_of_raw bad));
  Printf.printf "โœ“ All tests passed\n"

๐Ÿ“Š Detailed Comparison

Core Insight

`From<T>` defines how to create a type from T. `Into<T>` is the reverse view. Implementing `From` auto-provides `Into`. This replaces ad-hoc conversion functions with a unified protocol.

OCaml Approach

  • Manual conversion functions: `int_of_float`, `string_of_int`
  • No unified conversion trait
  • Module-level `of_` / `to_` conventions

Rust Approach

  • `impl From<Source> for Target`
  • `Into` comes free via blanket impl
  • `.into()` for ergonomic conversion
  • `TryFrom`/`TryInto` for fallible conversions

Comparison Table

FeatureOCamlRust
Conversion`of_string`, `to_int` functions`From`/`Into` traits
InfallibleManual function`From`/`Into`
FallibleReturn `option`/`result``TryFrom`/`TryInto`
AutoNo`Into` from `From`