21.9 Binding Values While Testing: The @
Pattern
The @
(“at”) operator lets you bind a value to a variable while simultaneously testing it against a pattern.
fn check_error_code(code: u16) { match code { // Match codes 400-499, bind the matched code to `client_error_code` client_error_code @ 400..=499 => { println!("Client Error code: {}", client_error_code); } // Match codes 500-599, bind to `server_error_code` server_error_code @ 500..=599 => { println!("Server Error code: {}", server_error_code); } // Match any other code other_code => { println!("Other code: {}", other_code); } } } fn main() { check_error_code(404); // Output: Client Error code: 404 check_error_code(503); // Output: Server Error code: 503 check_error_code(200); // Output: Other code: 200 }
Here, client_error_code @ 400..=499
first checks if code
is in the range. If yes, the value of code
is bound to client_error_code
for use within the arm. This is useful when you need the value that matched a specific condition (like a range or enum variant) within the corresponding code block.
It works well with simple values (integers, chars) and enum variants. Matching complex types like String
against literals using @
requires care; often, a combination of binding and a match guard is more idiomatic:
fn check_message(opt_msg: Option<String>) { match opt_msg { // Bind the String to `msg`, then use a guard to check its value Some(ref msg) if msg == "CRITICAL" => { println!("Handling critical message!"); } // Bind any Some(String) using `ref` to avoid moving the string Some(ref msg) => { println!("Received message: {}", msg); } None => { println!("No message."); } } } fn main() { check_message(Some("CRITICAL".to_string())); // Output: Handling critical message! check_message(Some("INFO".to_string())); // Output: Received message: INFO check_message(None); // Output: No message. }