Any difference between `core::mem::drop(val);` and `let _ = val`?;

I hope I didn't miss anything.

Yes.

drop(thing);    // A
let _ = thing;  // B
let _x = thing; // C

A drops the thing immediately, as soon as the function call ends. You can write your own.

fn my_drop<T>(_t: T) { /* just drops it when it goes out of scope */ }

B doesn't even move or otherwise bind thing, because the _ is special. So that's a no-op.

C does move thing into _x, but _x won't drop until the end of its scope. Variables are dropped in opposite order of declaration, so you may change drop order. But it won't drop immediately.


Examples:

Documentation:

https://doc.rust-lang.org/reference/destructors.html#drop-scopes

https://doc.rust-lang.org/reference/patterns.html#wildcard-pattern

4 Likes

Interestingly enough

thing;

and

drop(thing);

are the same though, as far as I know (except that the compiler likes to warn against the former, because it's less obvious what's going on).

10 Likes

Where can I find explanation of

thing;

in the Rust reference?

Good question. Let's look under statements... Statements - The Rust Reference

Should be an expression statement.

An expression statement is one that evaluates an expression and ignores its result.

Well, that's awfully vague. Might benefit from some improvement IMO. As of now, the precise nature of 'evaluate' is a bit unclear. Maybe considering the question whether or not an expression statement is an place expression context would technically answer this question a bit better. Let's see..

The evaluation of an expression depends both on its own category and the context it occurs within.

The following contexts are place expression contexts:

  • The left operand of a compound assignment expression.
  • The operand of a unary borrow, address-of or dereference operator.
  • The operand of a field expression.
  • The indexed operand of an array indexing expression.
  • The operand of any implicit borrow.
    The initializer of a let statement.
  • The scrutinee of an if let, match, or while let expression.
  • The base of a functional update struct expression.

So if we assume this list to be complete, expression statements are not in it, so this then applies Edit: wait, that's the other way around... instead this applies:

When a place expression is evaluated in a value expression context, or is bound by value in a pattern, it denotes the value held in that memory location. If the type of that value implements Copy, then the value will be copied. In the remaining situations, if that type is Sized, then it may be possible to move the value.

The TL;DR thus is that a value expression context moves it's operand, and both (the argument position of) a function call to drop, as well as an expression statements are such value expression contexts. So it's the same action in principle: evaluate to a value, possibly by moving out of a place if a place (e. g. a variable name) is what was provided. Then subsequently, both drop and expression statements ignore the value you give to them after evaluating it.

5 Likes

I was reminded of this when reading at drop order in std doc, so I experimented with various cases of drop order based on the doc's sample code:

#![allow(unused)]
struct Foo;

impl Drop for Foo {
    fn drop(&mut self) {
        println!("Dropping Foo!")
    }
}

struct Bar;

impl Drop for Bar {
    fn drop(&mut self) {
        println!("Dropping Bar!")
    }
}

fn drop_fn_drop() {
    println!("drop_fn_drop");
    core::mem::drop(Foo);
    core::mem::drop(Bar);
}

fn let_underscore_drop() {
    println!("let_underscore_drop");
    let _ = Foo;
    let _ = Bar;
}

fn let_underscore_name_drop() {
    println!("let_underscore_name_drop");
    let _foo = Foo;
    let _bar = Bar;
}

fn line_terminal_drop() {
    println!("line_terminal_drop");
    Foo;
    Bar;
}

fn main() {
    drop_fn_drop();
    let_underscore_drop();
    let_underscore_name_drop();
    line_terminal_drop();
}

The result is:

drop_fn_drop
Dropping Foo!
Dropping Bar!
let_underscore_drop
Dropping Foo!
Dropping Bar!
let_underscore_name_drop
Dropping Bar!
Dropping Foo!
line_terminal_drop
Dropping Foo!
Dropping Bar!

playground