1

I'm trying to sort a Vec of enums. Please ignore the sorting mechanism itself, this is just a stripped-down example.

use std::cmp::Ordering;

enum MyEnum {
    Option1,
    Option2,
}

fn main() {
    let mut my_list: Vec<MyEnum> = vec![MyEnum::Option1, MyEnum::Option2, MyEnum::Option1];

    // (1) - doesn't work
    my_list.sort_unstable_by(|a, b| match (*a, *b) {
        (MyEnum::Option1, MyEnum::Option1) => Ordering::Equal,
        (MyEnum::Option1, MyEnum::Option2) => Ordering::Less,
        _  => Ordering::Greater
    });
}

I get the following error:

error[E0507]: cannot move out of borrowed content
  --> src/main.rs:12:44
   |
12 |     my_list.sort_unstable_by(|a, b| match (*a, *b) {
   |                                            ^^ cannot move out of borrowed content

The following two variants work:

// (2)
my_list.sort_unstable_by(|a, _b| match *a {
    MyEnum::Option1 => Ordering::Less,
    MyEnum::Option2 => Ordering::Greater
});

// (3)
my_list.sort_unstable_by(|a, b| match (a, b) {
    (&MyEnum::Option1, &MyEnum::Option1) => Ordering::Equal,
    (&MyEnum::Option1, &MyEnum::Option2) => Ordering::Less,
    _  => Ordering::Greater
});

When I want to match a plain reference, I can dereference it (variant 2); why doesn't this work inside the tuple in variant 1?

I understand why 3 works, but struggle with understanding where exactly a move happens in 1 and how to do it differently.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
mrspl
  • 481
  • 1
  • 5
  • 10
  • This doesn't answer your question, but one way to work around this is to add `#[derive(Clone, Copy)]` on the enum. This makes the enum a copy type so you can move out of it and the original is still valid. – Ryan Jan 01 '18 at 14:39

1 Answers1

2

where exactly a move happens

A move happens where the compiler is pointing — *a. You are moving the contents of a into a brand-new tuple. You can't do that, so the compiler gives an error.

The ability to "dereference" the matched variable without really dereferencing it is some syntactic goodness provided by the compiler, but it's very limited. It doesn't "see into" the expression, it only looks at some select syntax constructions and knows to ignore them.

It's possible that the compiler could be enhanced to see these cases, but presumably the cost/benefit tradeoff isn't favorable at this point in time.

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • Ah, ok... thanks for the links, I didn't find them before posting the question, but especially the first one already answers my question. – mrspl Jan 01 '18 at 00:13
  • @mrspl if https://stackoverflow.com/q/43370054/155423 answers your question, then I can mark this question as a duplicate of that one, but you'll have to unaccept the answer before I can delete it. – Shepmaster Jan 01 '18 at 00:15
  • I'm not sure if it is really a duplicate of the other _question_. Only the second part of the _answer_ that you give there also happens to answer my question, although that was not explicitly what was asked in the other thread. Do you think I should still mark it a duplicate or just leave it like this? – mrspl Jan 01 '18 at 16:39