Implementing Enums in Golang
Get latest articles directly in your inbox
An enum (aka enumerator) is a data type consisting of a set of named constant values. Enums are a powerful feature with a wide range of uses. Go doesn’t support enums natively. There are ways to define enums a bit differently compared to other programming languages like Java. A very simple example of enum can be the 4 directions.
enum Direction would have 4 values:
- North
- West
- South
- East
Define Enums In Go
Let’s try to understand enum with an example. An enum for CardSuit
has 4 possible values and it can be defined as:
// Way to implement enum
type CardSuit int
const (
Spades CardSuit = 0
Diamond CardSuit = 1
Heart CardSuit = 2
Club CardSuit = 3
)
Problem
What if the set of values that you want to be a part of enum is big? It’s not feasible to manually maintain numbers. Another problem with this approach is handling the enum numeric values explicitly when you remove one or more values.
Solution: Using iota
To solve the problem above, Golang provides us with a keyword iota
that is a built-in, predeclared identifier that represents successive untyped integer constants. The iota
starts from zero and auto-increments as more values are added. Once you’ve defined iota
in your constant, it is not required with further values. You can read more about iota here.
type CardSuit int
const (
Spades CardSuit = iota
Diamond
Heart
Club
)
This works exactly as before but now you can remove or extend your enum without updates through out your code. But you must have notices that we have defined Weekday as int but what if we need a float or a string value for each enum type. We can always define a Float
or String
to solve this. Let’s add a method to return string values for our Weekday
enum.
package main
import "fmt"
type CardSuit int
const (
Spades CardSuit = iota
Diamond
Heart
Club
)
// returns corresponding string value to the CardSuit enum
func (c CardSuit) String() string {
switch c {
case Spades:
return "Spades ♤"
case Diamond:
return "Diamond ♢"
case Heart:
return "Heart ♥"
case Club:
return "Club ♧"
}
return "Unknown card suit"
}
func main() {
// define day of type CardSuit (enum)
var suit CardSuit
// initializing the day
suit = Heart
fmt.Printf("Suit is %s", suit.String())
}
In the above case, switch case seems to be a lot of work. Since we have iota
as index we could use a string slice directly.
func (c CardSuit) String() string {
return []string{"Spades", "Diamond", "Heart", "Club"}[c]
}
Points to Remember
You can use enum to include default/unknown values in enum as well and handle them in further implementation.
const ( Unknown CardSuit = iota Spades Diamond Heart Club )
Using
iota
some values can be skipped when defining enum types. In the example enum below, there is no value defined for value2
.type Vehicle int const( Car Vehicle = iota Bike _ Truck Ship )
Another usecase could be to have different increment counter instead of 1.
const ( Success = iota // iota = 0 initially Fail = iota + 2 // iota = 1 so 1 + 2 = 3 Pending = iota * 5 // iota = 2 so 2 * 5 = 10 )
Instead of defining enums as
int
orstring
, they can be defined as structs. An example for struct based enum in Go would look like this:type Vehicle struct { name string wheels int } func (v Vehicle) String() string { return v.name } func (v Vehicle) Wheels() int { return v.wheels } var ( Unknown = Vehicle{"", 0} Car = Vehicle{"car", 4} Bike = Vehicle{"bike", 2} Ship = Vehicle{"ship", 0} ) func main() { car := Car fmt.Printf("Wheels in %s: %v", car.String(), car.Wheels()) }
Resources
Popular Go Articles you make like
Books to learn Golang
Do explore articles on Golang and System Design. You’ll learn something new 💡
I hope you learned something new. Feel free to suggest improvements ✔️
I share regular updates and resources on Twitter. Let’s connect!
Keep exploring 🔎 Keep learning 🚀
Liked the content? Do support :)