Cannot move out of borrowed content


#1

I do not understand why this works:

enum Allergen {
    Cats=1,
    Chocolate=2,
}

fn is_allergic_to(n:i32, a: Allergen) -> bool {
    match n & (a as i32) {
        0 => false,
        _ => true,
    }   
}

fn main (){
    is_allergic_to(1, Allergen::Cats);
}

but this does not:

enum Allergen {
    Cats=1,
    Chocolate=2,
}

fn is_allergic_to(n:i32, a: &Allergen) -> bool {
    match n & (*a as i32) {
        0 => false,
        _ => true,
    }   
}

fn main (){
    is_allergic_to(1, &Allergen::Cats);

}

<anon>:7:16: 7:18 error: cannot move out of borrowed content 
<anon>:7 match n & (*a as i32) {

#2

You can’t move out of something that is borrowed, because the move would destroy it. The reason why it would work if you changed Allergen to i32 is that i32 implements Copy, so it can be copied without any risk of ending up with an invalid state. You can safely implement Copy (and clone) for Allergen as well, since it’s meant to represent a number, and your second piece would work perfectly. You would, in fact, not even have to take a reference if it’s Copy because copying it would not cost any more.


#3

It’s like if I borrowed a book from you and then burned the book. You’d rightfully be mad because I burned your book. It’d be okay if I burned my book but not your book. You’d be mad you (or someone else) didn’t enforce respectful behaviour towards your book.

In the same circumstance, Rust will actively enforce reasonable behaviour toward a borrow. When Rust recognizes a borrow, it forbids things which only the owner is allowed to do (such as taking possession of it); hence, this is borrowed, you cannot take ownership of it (that is, cannot move out of borrowed content).


#4

Thank you.
I guess I don’t understand how *a is “moving outside of borrowed content”.
I realize that a is borrowed, but I didn’t realize that I could not dereference it…


#5

Deriving the Copy trait solved my problem:

#[derive(Eq, PartialEq, Debug, Copy, Clone)]
enum Allergen {
    Cats=1,
    Chocolate=2,
}

fn is_allergic_to(n:i32, a: &Allergen) -> bool {
    match n & (*a as i32) {
        0 => false,
        _ => true,
    }   
}

fn main (){
    is_allergic_to(1, &Allergen::Cats);
}

#6

Just as a note, this isn’t always possible. For example, if your struct Allergen had contained a Vec, then deriving copy wouldn’t work and you would have to manually clone.