Reputation: 795
I have code like this:
enum Packet {
Quit,
Message {
text: String,
time: i32,
is_admin: bool,
},
}
It's convenient, but I don't like having nested structs like this. Imagine if I needed more items in this enum, then the Packet definition would be too large. So, is there a way for me to move the Message struct outside and just write its name somewhere in the definition of the Packet struct? I thought about doing something like this:
struct ChatMessage {
text: String,
time: i32,
is_admin: bool,
}
enum Packet {
Quit,
Message(ChatMessage),
}
(btw can I name the struct the same as the item in Packet (struct Message
, Message(Message)
)?)
But then I'd have to do let msg = message.0
or something like that. If this is the only solution - I'm okay with that, but I'd be happy if there was a more concise solution.
Upvotes: 5
Views: 4800
Reputation: 42462
It's convenient, but I don't like having nested structs like this.
It is not a nested struct, it's a struct-like variant.
So, is there a way for me to move the Message struct outside and just write its name somewhere in the definition of the Packet struct? I thought about doing something like this:
You can do exactly that, it works as-is, it's a very common pattern.
(btw can I name the struct the same as the item in Packet (struct Message, Message(Message))?)
Yes, there is literally no relationship between the two: Packet::Message
is a constructor for the Packet
enum, and Message
is an unrelated (but embedded) type.
But then I'd have to do let msg = message.0 or something like that.
Yes and no, enums require pattern matching of some sort, so in all cases you have to match your Packet
variants. With the first version you extract the variant's fields directly:
match packet {
Quit => todo!("something"),
Message { text, .. } => todo!("something with {}", text)
}
while with the second you extract the Message
, and from there its content:
match packet {
Quit => todo!("something"),
Message(m) => todo!("something with {}", m.text)
}
However patterns have effectively unlimited "depth" so you can do both at once just fine, it's just a bit more verbose:
match packet {
Quit => todo!("something"),
Message(ChatMessage { text, .. }) => todo!("something with {}", text)
}
demo (incomplete): https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=b2bdaf08c45424f507955790445cc2f9
Upvotes: 11