In Go, we do not have a native support for union types which can seem confusing given the role they play in the language that support them. However, do not be discouraged because Go has an extensive support for other types such as interfaces that allow us to quickly and efficiently create the union types with ease.
In this tutorial, we will explore about union types in Go. We will introduce you to union types and learn how to emulate them using other types.
What Are Union Types?
A union type refers to a data structure that can hold the values of different types but only contains one value of a specific type at any given type.
One of the major roles on union types is storing a value that can hold multiple distinct types. This differs from other native types such as structs or maps where the elements are of the same type.
Take for example a function that returns either an integer or a string based on a given condition. One of the most efficient way to represent such possible return values is a union.
Emulate the Union Types in Go
Let us explore the various methods and techniques that we can employ to build a union type in Go.
Using Interfaces
The most common way of building the union types in Go is taking advantage of interfaces. Interfaces allow us to define a set of methods that a type must implement.
Therefore, by defining multiple interfaces, each corresponding to a possible type in the union, we can create a union-like structure that serves a similar purpose.
Take for example the following code demonstration:
import "fmt"
type UnionInt struct {
Value int
}
type UnionString struct {
Value string
}
type UnionType interface {
isUnionType()
}
func (u UnionInt) isUnionType() {}
func (u UnionString) isUnionType() {}
func main() {
var u UnionType
u = UnionInt{Value: 42}
fmt.Println(u)
u = UnionString{Value: "Hello, World!"}
fmt.Println(u)
}
In the given example, we start by defining two types: UnionInt and UnionString that represents the possible values of a union.
We then create an interface called “UnionType” that acts as a marker for both of these types. By implementing the “isUnionType” method for each type, we ensure that they match the “UnionType” interface.
This essentially allows us to create a variable “u” of type “UnionType” that can hold either the UnionInt or UnionString.
Running the previous code should return the following:
{Hello, World!}
Using the Struct Tagging
The second common method that we can use to emulate a union type in Go is using the struct tagging. This method involves us creating a struct with tagged fields which tells the compiler of active type and storing the corresponding value.
Take the following example code:
import (
"encoding/json"
"fmt"
)
type Union struct {
Type string `json:"type"`
Integer int `json:"int,omitempty"`
String string `json:"string,omitempty"`
}
func main() {
intUnion := Union{Type: "int", Integer: 100}
stringUnion := Union{Type: "string", String: "Hello, World!"}
intJSON, _ := json.Marshal(intUnion)
fmt.Println(string(intJSON))
stringJSON, _ := json.Marshal(stringUnion)
fmt.Println(string(stringJSON))
}
What is happening in this case is that we start by setting up a struct with the fields of different types that represent the union which, in this case, are Integer and String.
You will also notice the “Type” field which indicates an active type. By setting the appropriate type field and basically adding the struct tags, we can marshal and unmarshal the “Union” struct to JSON which provides a union-like feature.
{"type":"string","string":"Hello, World!"}
Conclusion
In this tutorial, we learned all about Union types in the Go programming language. We also learned how we can use the interfaces and struct tagging to emulate a union type behavior in the language. We hope that this tutorial helped you.