_ is used when there is an input argument that you simple don't use and the way to tell the compiler about it is to add a _ you can also do _my_var as well for the same result.
That's not a pipe, that's the closure syntax. Also underscores are for wildcards. You can use wildcards here because you are not using the variables passed so it doesn't matter.
You can also use underscores to throw away type annotations you don't care about, for example:
let list = &[1u8, 2, 3, 4];
let v: Vec<_> = list.iter().map(|item| item + 1).collect();
collect turns an iterator of something into a collection, but it needs to know what type of collection to create. The compiler can already infer the type of the item, so the only additional info it needs is the type of the container. In this case, we're giving it the annotation "vector of type 'whatever, I don't care'", and letting the compiler fill in the "whatever" with the type it inferred already.
It's less to type, and less you need to change if you ever decide to change the type of list.
I believe _ is a little more special -- it's not a variable binding at all, but rather drops the assigned value right away. Whereas _my_var is a real binding that just doesn't issue any warning about being unused, but still doesn't drop until it goes out of scope (like any other variable).
Interesting - I tried a similar test using _ as a function parameter and it was dropped at the end.
Is this actually specd somewhere? I don’t see why either matters in terms of drop order or optimization.
Edit: for locals I guess this just leaves the rvalue alone and the _ isn’t considered an lvalue. But for function args it appears to have no difference.
But what about in function args, which is what @emoon was referring to (I believe)? I think for locals it makes sense - it’s truly just syntax to ignore the value and no different than just creating an rvalue without binding - it’s dropped at the end of the statement.
Oh, and Merry Christmas to whoever is celebrating it!
_ is just special in general. In all contexts where _ is allowed (which IIRC is just patterns and types), _ will pretty much always have behavior that is in some way distinct from e.g. _a, because _ is not an identifier. (you can't even match it with ident in a macro)
I did some more testing:
It seems the auto-dropping is only for let statements. match patterns of _ don't appear to drop anything, nor do if let or for (which are often understood to desugar into some form of match anyways).
It applies recursively to subpatterns. let (_, a) = tuple; will drop the first element.
Personally, I've never understood why let bindings even do this, since it can be a hazard for things like RAII locks if you're not aware of it. Besides, we have drop in the prelude, don't we?
No, it doesn't - that's not how _ works. let _ = <expr>; is exactly equivalent to <expr>;. There are some value category things going on here. I'd recommend trying out the following examples, to get more intuition:
struct D(i32);
impl Drop for D {
fn drop(&mut self) { println!("dropped {}", self.0); }
}
fn main() {
{
D(0);
let x = D(1);
let _ = D(2);
D(3);
let y = D(4);
let _ = D(5);
}
{
let var = D(0);
let _ = var;
var;
D(1);
}
}
I don't really feel like explaining what's going on here with the value categories, because that would require synthesis of difficult wording on my part. However, if you know C++, the rules are similar.
I’d say that’s poor code . Instead, wrapping that function into a struct that can be owned by the Mutex is more appropriate. Otherwise the two are disconnected and you can make an RAII mistake anyway without the compiler shouting about it.