A friend ran into an issue today with the following code:
let _ = x.lock();
This apparently secures a lock and then immediately drops it, cf. #10488. The following code holds onto the lock instead of dropping it:
let _lock = x.lock();
I found this surprising and was wholly unaware of this special meaning of the _ name, and going by the reactions of @alexcrichton and others in #10488, I'm not the only one. It's not the most Google-able topic, but I wasn't able to find documentation of this except in the issue referenced above. I have to wonder how much Rust code out there has a landmine like this buried somewhere inside, undiscovered. Not the best look for a language aiming at safety and concurrency.
I suggest doing one of the following:
let _ = foo();. One could argue that all such lines should be replaced by the more clear foo();.let _ = ... or remove it from the language entirely. Not likely post-stabilization and given that the previous discussion in #10488. However, I worry about Rust going the way of languages like C++ and accumulating a collection of misfeatures and "don't touch this" areas due to legacy reasons.Warn about uses of let _ = foo();. One could argue that all such lines should be replaced by the more clear foo();.
let _ = ... is commonly used to suppress the must_use warning.
I think it should be documented. For me it was kind of obvious as it was consistent with general behavior of _, but if it confused you then there are many people who it confused as well.
FWIW, it is somewhat documented in the book:
It鈥檚 worth noting that using _ never binds the value in the first place, which means that the value does not move:
_[...code...]_
This also means that any temporary variables will be dropped at the end of the statement:
// Here, the String created will be dropped immediately, as it鈥檚 not bound: let _ = String::from(" hello ").trim();
Yes, this is already described in the book, and that section is linked to from the syntax index. Not much more we can do here, I don't think.
There are still some things you could do:
Self and self are already keywords._ in a different color.As I understand _ has special semantics everywhere it is used. In patterns it does not bind a variable and in types it is a wildcard.
_ isn't a keyword, though.
Triage: this is already documented, closing!
Is this documented somewhere in version two of the book? I haven't been able to find it, and this caused me some frustration. At least not explicitly, maybe it would be possible to figure this out from "as a wildcard pattern that will match any value but not bind to the value", but it certainly isn't obvious and there isn't anything that calls out this potential footgun.
https://doc.rust-lang.org/stable/book/ch18-03-pattern-syntax.html?#ignoring-an-unused-variable-by-starting-its-name-with-_
Note that there is a subtle difference between using only _ and using a name that starts with an underscore. The syntax _x still binds the value to the variable, whereas _ doesn鈥檛 bind at all. To show a case where this distinction matters, Listing 18-21 will provide us with an error.
hmm, that was hard to find, especially since it is under the section about starting a name with _ instead of the section about using just "_". Also it doesn't say anything about the behavior wrt drop.
Most helpful comment
hmm, that was hard to find, especially since it is under the section about starting a name with _ instead of the section about using just "_". Also it doesn't say anything about the behavior wrt drop.