Destructing enums with Tuple vs c-like structs

Hello,

I am trying to understand the rationale behind the why the commented code below does not work.


#[allow(dead_code)]
enum Message {
   VariantA { x: i32, y: i32 },    // anonymoys c-like struct
   VariantB ( i32, i32 ),          // tuple struct
}

fn main() {
   
   let m = Message::VariantA {x: 1, y: 2};
   
   match m {
       Message::VariantA {x, y} => println!("Variant A: {}, {}", x, y),
       Message::VariantB (p, q) => println!("Variant B: {}, {}", p, q),
   }
   
   if let Message::VariantA {x, y} = m {
       println!("Variant A (Second Time): {}, {}", x, y);
   }
   
   // the following code fails to compile
   //match m {
   //    Message::VariantA {a, b} => println!("Variant A: {}, {}", a, b),
   //    Message::VariantB (p, q) => println!("Variant B: {}, {}", p, q),
   //}
   
   // the following code fails to compile
   //if let Message::VariantA {a, b} = m {
   //    println!("Variant A (Second Time): {}, {}", a, b);
   //}
}

Specifically speaking, it's allowed to destruct the tuple struct variant with variable names of my choice (this is easy to understand since there was no name defined for the members of the tuple struct). However, trying the same with c-like anonymous structs does not work.

Although not a blocker but the difference seems confusing and I want to understand the reasoning behind this.

It's because both of these do the same thing:

Message::VariantA {x, y} => ...
Message::VariantA {y, x} => ...

The order of the fields is irrelevant. If you want to rename them, you can do so like this:

Message::VariantA {x: a, y: b} =>

Just ambiguity and confusion, probably. Tuples (and tuple variants) are naturally ordered, structs (and variants) with named fields aren't. It would make rearranging the order of your named fields a breaking change.

// This has an existing meaning so it can't be the ordered interpretation
// If you misremembered or haven't memorized the fields, you'll be confused
//      if the ordered interpretation were a thing
let Message::VariantA { y, x } = m;

// This is ambiguous, or worse, confusing
let Message::VariantA { b, x } = m;

// And it would also be confusing generally
let m2 = m.clone();
let Message::VariantA { a, b } = m;
let x = m2.a;  // error, no such field
1 Like

Foo { x } always is a shorthand for Foo { x: x }. a: b binds the variable b into the field named a. This applies both struct and enum variant, and both expression and pattern.

Thanks for the explaination.

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.