One thing I always missed in Go was sum types. I’ve seen some discussion before. Although Go doesn’t have this as an explicit, native feature, I found a pattern that suits my needs by defining types and interfaces.
In the example below, I simulate a function that would load application resources, which can be extracted by ID, position or a string identifier. First, we define the interface and the subtypes:
type ( // Variant type for: ResId, ResPos, ResStr. Res interface{ implRes() } ResId uint32 ResPos uint32 ResStr string ) func (ResId) implRes() {} func (ResPos) implRes() {} func (ResStr) implRes() {}
The isRes()
function acts like a “tag” for each subtype.
Now, a function that receives the variant type:
func LoadResource(variant Res) { switch v := variant.(type) { case ResId: println("ID", uint32(v)) case ResPos: println("Position", uint32(v)) case ResStr: println("String", string(v)) default: panic("Res does not accept a nil value.") } }
Usage is now trivial:
LoadResource(ResId(2001)) LoadResource(ResPos(4)) LoadResource(ResStr("MY_ICON"))
It’s clean and it works remarkably well. I applied this technique in my Windigo library.