Underscore

From Rust Community Wiki
Jump to navigation Jump to search

The underscore (_) is a reserved identifier in Rust and serves different purposes depending on the context. It usually means that something is ignored.

Underscores in patterns[edit | edit source]

_ in a pattern is called a wildcard, because it matches anything:

match 42 {
    _ => println!("Wildcard matched"),
}

The wildcard is not a variable binding, because _ can't be used as a variable.

Underscores in let bindings[edit | edit source]

Since let accepts a pattern, let _ = can be used to ignore a #[must_use] value such as a ResultThis links to official Rust documentation in order to suppress compiler warnings.

let _ = std::fs::remove_file("file.txt"); // Ignore the result

Note that it's often better to unwrap the result instead, to make sure that errors aren't silently discarded.

Drop order for wildcard patterns[edit | edit source]

When a variable goes out of scope, it is dropped and its destructor is called, if it has one. However, _ patterns behave a bit different than variables. The reference states[1]:

Unlike identifier patterns, [the _ pattern] does not copy, move or borrow the value it matches.

In match, if let, while let and for blocks, values matched as _ are dropped after the variable bindings. For example:

match (Foo("a"), Foo("b"), Foo("c")) {
    (a, _, c) => {
        println!("match arm");
    } // c, a dropped here
} // b dropped here

Function/closure parameters that are ignored with _ have the same drop order as variables:

fn foo(a: Foo, _: Foo, c: Foo) {
    println!("function body");
} // c, b, a dropped here

foo(Foo("a"), Foo("b"), Foo("c"));

In let bindings, a _ pattern does nothing: let _ = foo(); is equivalent to just foo();, which drops the return value immediately.

fn foo() -> Result<Foo, ()> {
    Ok(Foo)
}

let _ = foo(); // value dropped here
println!("1");

Note that variables can be prefixed with a _ to silence "unused variable" warnings, but this does not affect drop order:

fn foo() -> Result<Foo, ()> {
    Ok(Foo)
}

fn main() {
    let x = foo();  // warning: unused variable: `x`
    let _x = foo(); // no warning
    println!("1");
} // x and _x are dropped here

Underscores in types[edit | edit source]

Underscores can be used to omit type declarations[2]. For example, it can be used to specify only part of a type, and let Rust infer the rest:

let v: Vec<_> = iter.collect();
// or:
let v = iter.collect::<Vec<_>>();

Anonymous lifetime '_[edit | edit source]

The anonymous lifetime can be used where an explicit lifetime must be specified, even though it is used only once[3][4]:

struct Foo<'a>(&'a str);

impl Foo<'_> {}

fn foo(s: &str) -> Foo<'_> {
    Foo(s)
}

The impl block above is more concise thanks to the anonymous lifetime. The foo() function's return type could just be written as Foo, but the anonymous lifetime makes it clearer that the struct borrows something.

Anonymous const items[edit | edit source]

const items can be anonymous, by writing _ instead of a name[5]:

const _: i32 = 5;

These aren't too useful though, since there is no way to use them at runtime. However, they can be used to evaluate something at compile time, e.g. to verify that something compiles.

References[edit | edit source]