commented: Not to nitpick but the last solution does not work for non-trivial values. The code in the article works because “()” is automatically a “Copy” value in Rust, and the code is copying other_field instead of moving them out of self. [1] To fix it, drop(self.watcher) instead. To be honest, I'm not quite Rust-fluent and didn't know “let _ = ... ” drops the value for you. But if I do need to depend on dropping order (which might suggest a concurrent environment or runtime-checked borrowing), I will try to be very explicit about every drop: ordering is mostly logical, where memory safety won't help a lot. [1] Rust playground: Simply making other_field a non-Copy value will break the compilation: “error[E0382]: use of partially moved value: self”. commented: Yeah, good catch, drop(self) is not a solution most of the time. In the actual code I chose the explicit drop. BTW the ordering "bug" did not affect the correctness but meant that HTTP connections were closed later than expected. commented: If I understand this correctly, the confusion is because of two completely different uses of _: matching _ means ignore this field completely (i.e., just leave it in the struct). matching _foo means move this field into the variable _foo, which has a _ just to avoid the unused variable warning. commented: What tipped me off was that this code worked as expected: let other_field = { let Server { watcher: _watcher, other_field } = self; other_field }; However, after changing _watcher into _, self was only partially moved into the inner scope. commented: This surprised me, more than I thought it would after reading the first paragraph. I was aware that let _ = my_fun(); drops the return value immediately, whereas let _unused = my_fun(); doesn't. And I thought I knew why, but it turns out I didn't. I'd internalised the idea that "_ is a pattern that matches anything and discards it.", but that's not how it works. Check it out: struct NonCopy(&'static str); impl Drop for NonCopy { fn drop(&mut self) { println!("{}", self.0); } } struct AlsoNotCopy(NonCopy); fn main() { let a = AlsoNotCopy(NonCopy("apple")); println!("0"); let _ = a; let _ = a;// These three don't move out of a, or drop it! let _ = a; let AlsoNotCopy(_) = a;// Neither does this. let _ = AlsoNotCopy(NonCopy("banana"));// This prints "banana" on this line // (because it's a temporary) println!("1"); drop(a); // You can still access "a" as a full variable. println!("2"); } This prints: 0 banana 1 apple 2 Rust Playground _ doesn't move or discard anything at all! The reason that assigning to an underscore sometimes drops is because you're assigning a temporary! commented: It feels like everyone ends up discovering this at some point... now, usually someone would've probably added a lint by now, but at least I don't see a way of writing a lint that would pick this up. commented: Yes, it's a pitfall, but any idiomatic Rust design API should tie what is being protected to the guard's lifetime, so it has to access through the guard, as e.g. in Mutex's guards. This makes this pitfall impossible. "Dettached" guards/watchers are an anti-patter in Rust. .