Note: None of this capability is currently implemented.
Unions are useful when we want a value to be represented by one of several variant struct types. For example, consider this union type:
union Point: struct XyPoint: x f32 y f32 struct AngPoint: dist f32 angle f32
This defines a new union type called Point which holds a single point value. At any given point in time, that value would either be an XyPoint or a AngPoint value.
There are two interesting properties important to know about unions:
- These are discriminated unions: there is a hidden "tag" field at the beginning of the value
which is used at runtime to distinguish which of the variant types the value belongs to.
This tag field would effectively hold a 0 for an XyPoint and 1 for a AngPoint.
Note: The hidden tag field is implicitly positioned as the first field. If one wishes to place it in a different spot, explicitly specify the tag field (_ enum) in the place where it is desired.
- All variant structs in a union occupy the exact same size of memory. This size is the size of the largest struct plus the size of the tag field. Any smaller structs are padded to fit.
- All the variant types are considered part of the module namespace rather than part of the union namespace, which means they can be used directly without the need to qualify the name with the name of the union.
To create variant types who sizes vary, or whose number of variants is open-ended, use a variant trait instead of a union.
Declaration
As the above example shows, the simplest form of a union type declaration is as easy as packaging several struct definitions inside an overall named union declaration block. It is permissible for any of these structs to be empty of fields, as the presence of the tag field ensures that the overall struct is not empty.
Any number of fields may be specified prior to the first struct declaration. All these fields are considered in common and at the beginning across all the variant structs.
union Event: time datetime struct ButtonEvent: button u8 pushed Bool struct KeyEvent: key Unicode struct QuitEvent
In this example, all three variant structs include the time field prior to any fields they have defined.
For alignment reasons, it may be desirable to place the implicit tag field in some other spot other than the first field. To do this, specify an anonymous field of _ enum wherever the tag field should be located. The size and type of the tag field can vary depending on the number of variants (e.g., u8 when variant count is 255 or less). The tag field cannot be explicitly accessed, referenced or mutated.
Initialization
An union initial value is built using a constructor for one of the variant struct types:
mut event = QuitEvent[timestamp] oddval = KeyEvent[timestamp, 's']
Notice that the constructor must specify a value for all common fields. It can never specify a value for the hidden tag field, as that is determined by the variant type selected.
Copying
A union value may be passed around, by copy, just like any other value. This is possible because all variant values of a specific enum type are the same size. The enum type's size is effectively the size of its largest variant type plus the size of its hidden tag field.
Value Access
To safely gain access to the differently-typed value enclosed with an enum value, we must use pattern matching to determine which variant type it holds. Once that has been narrowed, it can be used like any other struct value.
Comparing
An enum value may only be compared for equivalence (and not order). The equivalence check compares the tag fields first. If they are equal, the appropriately-typed interior values are compared using the == method.