Shiraaz Moollatjie
Posted on November 13, 2019
This article will look at how to represent enums in go. It will also add some practical advice as well.
An enum is a datatype that consists of a set of named values. Many languages use the enum
keyword to represent enum types.
Use iota
to define enums
According to the Go specification, iota
is a keyword that represents successive untyped integer constants as long as those constants are in the same constant declaration
.
For example, we can define the following set of constants from c0 -> c2
:
const (
c0 = iota // c0 == 0
c1 = iota // c1 == 1
c2 = iota // c2 == 2
)
We can reduce the amount of code written by removing the excess iota
declarations:
const (
c0 = iota
c1
c2
)
The iota
keyword also lets us define specific patterns with your constants, but in this article we are only focusing on enums
.
Applying this in practice
So let us apply this in practice. We will use the example of card suites. So we define a suite of cards:
type Suite int
const (
unknown Suite = iota
Spades
Hearts
Diamond
Clubs
sentinel
)
Because our eyes are so sharp, you'd notice that I added two new values to this list: An unknown
and a sentinel
value. Let us work through their value.
Using unknown
and sentinel
values
Within go, generally we want our enum type to be able to support zero values. This makes it easier to write idiomatic go without worrying about processing business logic for zero values.
There are cases where zero values needs to be supported (e.g. for some externally defined protocol or even legacy code), but within our own application code we try to prevent it.
The purpose of the sentinel
is to make it easy to iterate and validate our list of enum values. It also adds to the maintainability of our enums.
For example, because Suite
is it's own type, we can in theory assign it any value. So let's try to validate that an integer is within our list of enums:
func (s Suite) isValid() bool {
return s > unknown && s < sentinel
}
As you can see, our validation code is agnostic of the specific values of our suites. This means that we are able to add values to our enums as long as they appear before
our sentinel value.
Deprecating enums?
If your system is small, then this wouldn't really apply. However, suppose you do not want to support certain types for whatever reason. Go actually makes this very easy by using _
values. So let's say that we only want to use the black Suites
, but we need to keep the red Suites
for historical purposes. We simply do this:
type Suite int
const (
unknown Suite = iota
Spades
_
_
Clubs
sentinel
)
Using this way, we are maintaining the Clubs
data throughout the lifetime of our application, and we will be able to catch all the usages of the red Suite
values during refactoring.
Conclusion
In this post we looked at how to define enums in go using the iota
keyword with our constants. We also recommended the use of an unknown
value and a sentinel
value to make application programming easier. We even took a look at possibly deprecating enum
values in our application.
Posted on November 13, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.