ExamplesBy LevelBy TopicLearning Paths
566 Fundamental

Nested Patterns

Functional Programming

Tutorial Video

Text description (accessibility)

This video demonstrates the "Nested Patterns" functional Rust example. Difficulty level: Fundamental. Key concepts covered: Functional Programming. Real data structures are rarely flat — they are trees: enums containing structs containing options containing results. Key difference from OCaml: 1. **Struct syntax**: Rust `Outer { inner: Inner { value } }` uses braces; OCaml `{ inner = { value } }` uses `=` for record fields.

Tutorial

The Problem

Real data structures are rarely flat — they are trees: enums containing structs containing options containing results. Nested patterns allow matching deeply nested structures in a single expression, extracting values from multiple levels simultaneously. Without nested patterns, extracting a value from Some(Some(Point { x, y })) would require multiple nested match statements. Nested patterns are essential in AST traversal, JSON processing, configuration parsing, and any domain with layered data.

🎯 Learning Outcomes

  • • How Outer { inner: Inner { value } } matches and extracts from nested structs
  • • How Some(Some(v)) matches and extracts from nested Option
  • • How Ok(Ok(v)) and Ok(Err(msg)) handle nested Result
  • • How to combine struct destructuring, enum variants, and tuple patterns in one expression
  • • Where nested patterns appear: AST traversal, JSON manipulation, nested configuration
  • Code Example

    #![allow(clippy::all)]
    //! Nested Patterns
    //!
    //! Matching deeply nested structures.
    
    #[derive(Debug)]
    pub struct Outer {
        pub inner: Inner,
    }
    #[derive(Debug)]
    pub struct Inner {
        pub value: i32,
    }
    
    /// Match nested struct.
    pub fn get_value(o: &Outer) -> i32 {
        match o {
            Outer {
                inner: Inner { value },
            } => *value,
        }
    }
    
    /// Nested Option.
    pub fn unwrap_nested(opt: Option<Option<i32>>) -> i32 {
        match opt {
            Some(Some(v)) => v,
            Some(None) => -1,
            None => -2,
        }
    }
    
    /// Nested Result.
    pub fn process_nested(res: Result<Result<i32, &str>, &str>) -> i32 {
        match res {
            Ok(Ok(v)) => v,
            Ok(Err(_)) => -1,
            Err(_) => -2,
        }
    }
    
    /// Deeply nested.
    pub fn deep_match(data: Option<(i32, Option<(i32, i32)>)>) -> i32 {
        match data {
            Some((a, Some((b, c)))) => a + b + c,
            Some((a, None)) => a,
            None => 0,
        }
    }
    
    #[cfg(test)]
    mod tests {
        use super::*;
    
        #[test]
        fn test_get_value() {
            let o = Outer {
                inner: Inner { value: 42 },
            };
            assert_eq!(get_value(&o), 42);
        }
    
        #[test]
        fn test_unwrap_nested() {
            assert_eq!(unwrap_nested(Some(Some(5))), 5);
            assert_eq!(unwrap_nested(Some(None)), -1);
            assert_eq!(unwrap_nested(None), -2);
        }
    
        #[test]
        fn test_process_nested() {
            assert_eq!(process_nested(Ok(Ok(10))), 10);
            assert_eq!(process_nested(Ok(Err("e"))), -1);
            assert_eq!(process_nested(Err("e")), -2);
        }
    
        #[test]
        fn test_deep_match() {
            assert_eq!(deep_match(Some((1, Some((2, 3))))), 6);
            assert_eq!(deep_match(Some((5, None))), 5);
            assert_eq!(deep_match(None), 0);
        }
    }

    Key Differences

  • Struct syntax: Rust Outer { inner: Inner { value } } uses braces; OCaml { inner = { value } } uses = for record fields.
  • Pattern depth: Both languages support arbitrarily deep nested patterns with the same compile-time exhaustiveness checking.
  • Readability: Very deep nesting can become hard to read in both — the ? operator and and_then chains are often cleaner for nested Option/Result.
  • Performance: Nested patterns compile to nested conditional jumps — the same as explicit nested match but without the code duplication.
  • OCaml Approach

    OCaml nested patterns are identical in expressive power:

    let get_value { inner = { value } } = value
    let unwrap_nested = function
      | Some (Some v) -> v
      | Some None -> -1
      | None -> -2
    

    The syntax differs slightly but the capability is the same.

    Full Source

    #![allow(clippy::all)]
    //! Nested Patterns
    //!
    //! Matching deeply nested structures.
    
    #[derive(Debug)]
    pub struct Outer {
        pub inner: Inner,
    }
    #[derive(Debug)]
    pub struct Inner {
        pub value: i32,
    }
    
    /// Match nested struct.
    pub fn get_value(o: &Outer) -> i32 {
        match o {
            Outer {
                inner: Inner { value },
            } => *value,
        }
    }
    
    /// Nested Option.
    pub fn unwrap_nested(opt: Option<Option<i32>>) -> i32 {
        match opt {
            Some(Some(v)) => v,
            Some(None) => -1,
            None => -2,
        }
    }
    
    /// Nested Result.
    pub fn process_nested(res: Result<Result<i32, &str>, &str>) -> i32 {
        match res {
            Ok(Ok(v)) => v,
            Ok(Err(_)) => -1,
            Err(_) => -2,
        }
    }
    
    /// Deeply nested.
    pub fn deep_match(data: Option<(i32, Option<(i32, i32)>)>) -> i32 {
        match data {
            Some((a, Some((b, c)))) => a + b + c,
            Some((a, None)) => a,
            None => 0,
        }
    }
    
    #[cfg(test)]
    mod tests {
        use super::*;
    
        #[test]
        fn test_get_value() {
            let o = Outer {
                inner: Inner { value: 42 },
            };
            assert_eq!(get_value(&o), 42);
        }
    
        #[test]
        fn test_unwrap_nested() {
            assert_eq!(unwrap_nested(Some(Some(5))), 5);
            assert_eq!(unwrap_nested(Some(None)), -1);
            assert_eq!(unwrap_nested(None), -2);
        }
    
        #[test]
        fn test_process_nested() {
            assert_eq!(process_nested(Ok(Ok(10))), 10);
            assert_eq!(process_nested(Ok(Err("e"))), -1);
            assert_eq!(process_nested(Err("e")), -2);
        }
    
        #[test]
        fn test_deep_match() {
            assert_eq!(deep_match(Some((1, Some((2, 3))))), 6);
            assert_eq!(deep_match(Some((5, None))), 5);
            assert_eq!(deep_match(None), 0);
        }
    }
    ✓ Tests Rust test suite
    #[cfg(test)]
    mod tests {
        use super::*;
    
        #[test]
        fn test_get_value() {
            let o = Outer {
                inner: Inner { value: 42 },
            };
            assert_eq!(get_value(&o), 42);
        }
    
        #[test]
        fn test_unwrap_nested() {
            assert_eq!(unwrap_nested(Some(Some(5))), 5);
            assert_eq!(unwrap_nested(Some(None)), -1);
            assert_eq!(unwrap_nested(None), -2);
        }
    
        #[test]
        fn test_process_nested() {
            assert_eq!(process_nested(Ok(Ok(10))), 10);
            assert_eq!(process_nested(Ok(Err("e"))), -1);
            assert_eq!(process_nested(Err("e")), -2);
        }
    
        #[test]
        fn test_deep_match() {
            assert_eq!(deep_match(Some((1, Some((2, 3))))), 6);
            assert_eq!(deep_match(Some((5, None))), 5);
            assert_eq!(deep_match(None), 0);
        }
    }

    Deep Comparison

    OCaml vs Rust: pattern nested

    See example.rs and example.ml for implementations.

    Exercises

  • Three-level nest: Create struct A { b: Option<B> }; struct B { c: Vec<C> }; struct C { value: i32 } and write a function that extracts the first C.value if all levels are present.
  • Nested config: Implement a Config { database: Option<DbConfig { host: String, port: u16 }> } and write fn db_host(c: &Config) -> Option<&str> using a single nested pattern.
  • AST node: Define a simple arithmetic AST Expr { Add(Box<Expr>, Box<Expr>), Lit(i32) } and write an eval function using nested match patterns.
  • Open Source Repos