Tricky quiz question

Here's some code from Rust quiz:

struct S;

impl Drop for S {
    fn drop(&mut self) {
        print!("1");
    }
}

fn main() {
    let s = S;
    let _ = s;
    print!("2");
}

Basically, the core question here is whether s in let _ = s; is moved or not. It turns out it does, but I can't figure why.

In my understanding, a type either implements Copy and then its instances are not moved when appear on the right side of = or it doesn't implement Copy and its instances ought to be moved.

My first theory of unit structs being Copy by default does not hold since this snipped fails to compile:

struct S;

fn foo<T: Copy>(_t: T) {}

fn main() {
    foo(S)
}

Therefore, it must be something with underscore assignment. What is it?

I made a quick test, and the let _ = s; doesn't move out the s. What makes you think in opposite?

What makes you think in opposite?

Citing myself

In my understanding, a type either implements Copy and then its instances are not moved when appear on the right side of = or it doesn't implement Copy and its instances ought to be moved.

S doesn't implement Copy

For example, if we replace let _ with let _a then it IS moved

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=8333822ebc43a612739d8bec6c6078b7

It's confusing, because let _ = S (note: constructor) does destroy it immediately, unlike let _s = S. So it's easy to think of let _ as immediately-destroying construct (which was my assumption too!) rather than some kind of a do-nothing pattern.

Destroying implies moving, right? In order to destroy something, we need to own it. Therefore, we need to move it.

Both dropping and moving require owning and no live references to the object, but I don't think destruction strictly speaking counts as a move (e.g. other than packed structs, it doesn't require copying anything. There's drop_in_place which doesn't perform any moves).

// move a to something
let something = a;

// don't do anything (noop)
// 
// if a is _rvalue_ (or how Rust calls it?) than it'll be dropped right away 
// because there are no other bindings to it and _ doesn't create one
// if a is _lvalue_ (place), _ doesn't do a thing because there are other bindings
// and no extra bindings are created
let _ = a;

So, _ is a very especial place that turns any let into "compute the rval but do not bind" noop, is that right?

Yes, these two are always equivalent:

let _ = some_expression;
some_expression;

The only difference is that the latter will sometimes emit a warning, that the former would supress, e.g. if the expression was equal to a Result.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.