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.
}