0

Consider the following snippet:

use std::fmt;

enum TestEnum {
    StructMem {value: i32, is_valid: bool},
    RandoMem,
}

impl fmt::Display for TestEnum {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        use TestEnum::*;
        match self {
            StructMem {value, is_valid} => {
                if *is_valid { // Why dereference is_valid ?
                    write!(f, "f")?
                }
                write!(f, "{:?}", value)
            }
            RandoMem => {
                f.write_str("Random")
            }
        }
    }
}

Why do I need to dereference is_valid in the if statement?

EDIT: This question What is the syntax to match on a reference to an enum? seems to be dealing with a similar situation, but the answers are all focused on solving the specific issue (which does not involve a struct) and are not explaining the ownership/binding semantics.

Vikash Balasubramanian
  • 2,921
  • 3
  • 33
  • 74
  • Does [this answer](https://stackoverflow.com/a/51111291/9716597) of the question [What is the syntax to match on a reference to an enum?](https://stackoverflow.com/questions/36590549/what-is-the-syntax-to-match-on-a-reference-to-an-enum) help? – L. F. Feb 15 '21 at 02:06
  • @L.F. nope, the question is pretty similar and deals with the same situation, but the particular necessity for dereferencing is not really explained in any of the answers – Vikash Balasubramanian Feb 15 '21 at 03:29
  • Indeed, the explanation is in the [match ergonomics RFC](https://rust-lang.github.io/rfcs/2005-match-ergonomics.html) referred to by the answer. – L. F. Feb 15 '21 at 06:16

2 Answers2

3

This is not specific to the match or the enum but due to the signature of fmt(), which takes self as a reference (&self instead of self, if ownership was taken).

The match self, therefore, already refers to a borrowed instance of TestEnum and the match-arm StructMem {value, is_valid} binds via references (&i32, and &bool). This is why is_valid ends up being a &bool, not a bool.

user2722968
  • 13,636
  • 2
  • 46
  • 67
1

When you pattern match a reference and de-structure it you can only get references of the inner members, otherwise you'd be moving the inner members out of an immutable reference which would violate Rust's ownership rules. Here's a simpler example:

struct Container(Vec<i32>);

fn get_inner_vec(c: &Container) -> &Vec<i32> {
    // v MUST BE a reference
    // otherwise this destructing would somehow be moving the Vec
    // outside of an immutable borrow of Container
    let Container(v) = c;
    v
}
pretzelhammer
  • 13,874
  • 15
  • 47
  • 98