You can also build enums by building a struct with a `Tag` field. This works well and generally has better performance characteristics than using interfaces.
That approach has its own problems, such as wasting memory (need to store any data for each tag value separately, rather than benefiting from overlapping storage ala Rust enums or C tagged unions), as well as losing type safety: one has to manually remember which (groups of) fields correspond to which tag values (although the Go loss of type safety is far better/more controlled than the one for C tagged unions). Using interfaces has neither of these problems.
Note that using interfaces doesn't get you all the type safety either, since there's no exhaustive matching. But it's good enough (aside from the possible perf issues) for most use cases.
> Of course they are. What if you read from or write to the wrong field?
This falls under the rubric of "not meaningfully less type safe". This data structure is central in a large project of mine, and I have maybe 3 places where I switch on the type flag. I'm not proposing this as a general purpose replacement for interfaces, only a useful way to abstract over a few known types when you can't afford all of the allocs.
> Your example has one contained type per variant. In Rust it is common to have an enum like
enum Foo {
Variant1(String, u8, Vec<u8>),
Variant2(u8),
Variant3(String),
Variant4(f32),
Variant6(f32)
Variant5(bool, bool, String)
}
I agree. I don't propose this as a general purpose replacement for Rust's enums.
> I agree. I don't propose this as a general purpose replacement for Rust's enums.
Yeah, that's the thing, Rust enums used this way are very powerful. I'm fine with making tagged structy things in cases like the one mentioned, I feel Go can handle that. I'm missing out on all the useful stuff I can do with proper algebraic datatypes.
That only works well if each "variant" holds the same kind of thing. If not, you have to store them one after the other (space wastage), or use interfaces to store them in the same place (tag isn't necessary anymore, extra boxing).
Rust enums (ADTs) aren't like Java enums where each variant contains the same kind of data.