rust

Why does Drop take &mut self instead of self?


Why does Drop’s method have signature fn drop(&mut self) instead of fn drop(self)? This makes it difficult to move values out of the fields e.g. self.join_handle.join() or std::mem::drop(self.file) (error: cannot move out of type X, which defines the Drop trait).


Solution

  • Let's look at how std::mem::drop is implemented:

    pub fn drop<T>(_x: T) { }
    

    That's right: it's an empty function! That's because it takes advantage of move semantics to acquire ownership of its argument. If T implements Drop, the compiler automatically inserts a call to Drop::drop(_x) at the end of the function. This happens to all arguments received by value (that is, in fact, all arguments whatsoever, but dropping a reference doesn't drop the referent).

    Now consider what would happen if Drop::drop took its argument by value: the compiler would try to invoke Drop::drop on the argument within Drop::drop — this would cause a stack overflow! And of course, you would be able to call mem::drop on the argument, which would also try to recursively call Drop::drop.