The variants of an enum live in their own namespace, so the variants of Message
are Message::Quit
and so on. The variants act similar to types for things like pattern matching and value construction, but are not distinct types -- a Message::Quit
has type Message
, as does a Message::Echo(_)
, etc.
When you have a value of type Message
, it's going to be one of the variants. It doesn't have any fields that you can access with .
. If it happens to be a data-carrying variant, you have to use something like pattern matching to pull it out, to ensure that you're dealing with the correct variant. So for example:
let message = Message::Echo("foo".to_string());
// other_message has type Message, and after assignment
// is the variant Message::Echo
let other_message = message;
// If you wanted to get the data out
let mut inside_data = String::new();
if let Message::Echo(data) = other_message {
inside_data = data;
}
And for non-data carrying variants, it works similarly...
let message = Message::Quit;
// other_message has type Message, and after assignment
// is the variant Message::Quit
let other_message = message;
But there isn't any data to get out. But also since they have no data, you can always just create a new Message::Quit
on the fly.
enum
s don't have fields and make you match on variants because they are tagged unions, and safety demands that you always dynamically check what variant you have. If you have a Message::Echo
, you definitely can't also have a Message::Quit
, so they act less like fields. This is in contrast with untagged unions, where the compiler doesn't know what variant you have, and you treat them like fields. (Rust has unions too, for FFI reasons mainly, but they are unsafe to use.)
(There's also some desire to turn enum
variants into they're own types, but this would be a large change and isn't likely any time soon.)
You can import from an enum
namespace too, for example:
fn foo(message: Message) {
use Message::*;
match message {
// No need for Message::Name anymore
ChangeColor(tuple) => {},
Quit => {},
_ => { /* etc */ },
}
}
Which you're probably already using all the time with Result
s (Ok(_)
, Err(_)
) and Option
s (Some(_)
, None
).
If they had declared it
// ...
ChangeColor(u8, u8, u8),
// ...
You wouldn't need a tuple. But they defined it as a single value that is a tuple. Perhaps it's common for the code in question to be passing around such tuples.
I haven't looked at the problem they gave, but if self.quit
is a bool
, you probably want something like
Message::Quit => self.quit = true,
There is no "content" to a Message::Quit
beyond the fact that it's the Quit
variant of a Message
. You could assign it to a variable of type Message
(or just as easily assign Message::Quit
to a variable of type Message
). But it carries no extra data, so if you need to infer some sort of data like a bool
, you have to supply that data explicitly -- there's nothing there to be pulled out of the variable itself.