Rust Ignoring Values in Patterns
Ignoring a value in a pattern means matching it without binding it. The underscore _ is the plainest form, matching anything and binding nothing.
Skip one piece with _
An underscore matches anything and binds nothing — the value is not saved anywhere:
let (first, _, third) = (10, 20, 30);
println!("{first} and {third}");Ignore a whole parameter
A signature sometimes demands a value your code does not need. An underscore parameter accepts it and throws it away — common when implementing a trait:
fn describe(_: i32, label: &str) {
println!("label = {label}");
}
describe(7, "go");An underscore name still binds
A name like _t only silences the unused-variable warning — the value really moves into it. Compare the two halves:
let a = Some(String::from("hi"));
if let Some(_) = a {
println!("a still usable: {}", a.is_some());
}
let b = Some(String::from("hi"));
if let Some(_t) = b {
println!("b was moved into _t");
}Ignore the rest of a struct with ..
Point3 is a struct with x, y and z fields — it appears in the full example below. Two dots stand for every field you did not name:
let p = Point3 { x: 1, y: 2, z: 3 };
let Point3 { x, .. } = p;
println!("x = {x}");Skip the middle of a tuple with ..
The same two dots work inside a tuple pattern, skipping a whole run in the middle:
let ends = (1, 2, 3, 4, 5);
let (first, .., last) = ends;
println!("{first}..{last}");Example
struct Point3 { x: i32, y: i32, z: i32 }
fn describe(_: i32, label: &str) {
println!("label = {}", label);
}
fn main() {
describe(99, "ready");
let numbers = (2, 4, 8, 16, 32);
match numbers {
(first, _, third, _, fifth) => println!("some: {}, {}, {}", first, third, fifth),
}
let origin = Point3 { x: 0, y: 0, z: 0 };
match origin {
Point3 { x, .. } => println!("x is {}", x),
}
let s = Some(String::from("Hello!"));
if let Some(_) = s { println!("found a string"); }
println!("s is still here: {:?}", s);
}Key points
- .. may appear only once in a tuple pattern: (.., second, ..) is rejected, because Rust cannot tell which piece second should be
In this example, each ignoring tool does its own job. describe takes _: i32, so the 99 is accepted and thrown away, and only the label prints. The tuple pattern keeps first, third, and fifth — 2, 8, and 32 — and skips 4 and 16 with _. The struct pattern Point3 { x, .. } reads x and lets .. cover y and z. Last, Some(_) tests that s holds text. It tests without binding it. So s is never moved. The final line can still print it. It prints s is still here: Some("Hello!").
Note
Prefer _ when you truly ignore a value.
Use an underscore name only in one case.
The value must be held for later.
The compiler reads the difference, even when readers skim it.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Rust Playground
Exercise
What is the difference between _ and _s in a pattern?