21.3 Refutable vs. Irrefutable Patterns

A crucial concept is the distinction between refutable and irrefutable patterns:

  • Irrefutable Patterns: These patterns are guaranteed to match any value of the expected type. Examples include binding a variable (let x = value;), destructuring a struct (let MyStruct { field1, field2 } = s;), or a tuple (let (a, b) = tuple;). Irrefutable patterns are required in contexts where a match failure is not meaningful or allowed, such as:

    • let statements
    • Function and closure parameters
    • for loops
  • Refutable Patterns: These patterns might fail to match a given value for a specific type. Examples include matching a literal (42 only matches the value 42), an enum variant (Some(x) doesn’t match None), or a range (1..=5 doesn’t match 6). Refutable patterns are used in contexts designed to handle potential match failures:

    • match expression arms (except potentially the final wildcard _ arm)
    • if let conditions
    • while let conditions
    • let else statements

The compiler enforces this distinction. Trying to use a refutable pattern where an irrefutable one is needed (e.g., let Some(x) = option_value;) results in a compile-time error because the code wouldn’t know what to do if option_value were None.