Is there a convention for unused variables? e.g. "_"

Heyo!

Was working on a thing and I made a for value in 1...x loop, and was curious if there's a standard for unused variables since I'm not using value. Is it just _ ?

Use clippy for linting your code. It will tell you pretty much what the convention is. But for all purposes and needs, yes, either _ or if you want a more descriptive name, just prefix your variable name with an _.

4 Likes

There is a semantic difference between these two options: if you use _ as a name, the corresponding value will be Dropped immediately; this is not the case with _name, where normal Drop rules apply (at the end of the current block).

11 Likes

Make sure to read the compiler warnings:

warning: unused variable: `x`
 --> src/main.rs:2:9
  |
2 |     for x in 0..10 {
  |         ^ help: if this is intentional, prefix it with an underscore: `_x`
  |
  = note: `#[warn(unused_variables)]` on by default

So the way to say "intentionally unused" is to prefix it with an underscore.

You can also use _ as a pattern to not have a binding at all.

4 Likes

Actually no, the value will not even be moved! _ is not a variable name, it's a pattern that matches everything but doesn't take over the value.

fn main() {
    let a = vec![1, 2, 3];
    let _ = a; // does nothing
    // Haha, I am still here!!!
    println!("{}", a.len());
}
21 Likes

And because this is often surprising to people at the top level, it's really important that it work this way when it's nested. For example,

if let opt @ Some(_) = returns_option_of_string() {

only works because the _ doesn't bind the inside of the option.

(And for orthogonality, it does the same thing even when not nested.)

3 Likes

Thank you for the answers everyone!

So, overall, what is good practice for using _ ? When should you avoid it, and when should you use it?

1 Like

Prefer _ for "I really don't care" local variables, like for _ in 0..n.

The only place you use let _guard = …; is in special scope-based resource management scenarios where you need the guard to live despite not using it. That should be rare.

4 Likes

One such rare instance: I made the mistake of thinking _ was equivalent to _foo a while back. I was using drop_guard to clean up partially initialized data on error, and made the mistake of thinking that let _ = drop_guard::guard(&status, ...); expressed that I want to keep the returned object around until it goes out of scope, but I don't actually want to use it.

1 Like

One thing you can consider for those cases: calling drop on it manually to help make it extra-clear that you're caring about where the drop happens, and that it's important that it not be let _ =.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.