Is there enumeration in Go? This is an ambiguous question. Some say it has, others say it doesn't.
What is enumeration
Code is abstract from reality. The concept of enumeration in program and life is the same: enumeration represents the collection of all possible values of an object. For example, SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY and SATURDAY representing the week are a set of enumeration values.
In fact, we can think of all primitive types in Go as an enumeration. For example, bool type can be considered as an enumeration that can only be true or false; Enumeration with byte type of 0 to 255; A pointer is an enumeration of all possible memory addresses in a 32-bit or 64 bit address space.
In languages such as Python, Java and C, enum keywords or classes are generally provided for developers to implement enumeration.
The general pseudo code can be expressed as follows
enum Enumeration name{
identifier ①[=Integer constant],
identifier ②[=Integer constant],
...
identifier N[=Integer constant],
}Enumerating variables;
Go has no enum keyword. However, we can observe the characteristics of enumeration: the same set of enumeration values should not be changed after definition; The data type corresponding to the enumeration value should be the same; Enumeration values are finite; Enumeration values correspond to their meanings one by one.
According to the above characteristics, in Go, const and iota keyword to implement enumeration.
iota
const is used to define constants that are created at compile time and cannot be modified at run time. Only Boolean, numeric (integer, floating point and complex) and string types can be defined as constants.
The constant declaration format is as follows
const identifier [type] = value
Iota is a constant counter, which is reset to 0 when it encounters the const keyword. When const adds a line of constant declaration (including the blank identifier), the iota count will increase by 1.
const (
A int = iota // 0
_
B // 2
C // 3
D // 4
)
const (
E int = iota // 0
F // 1
)
Go enumeration implementation
With the participation of iota, if you want to enumerate week values in Go, we can define them as follows
type Weekday int
const (
_ Weekday = iota // ignore first value by assigning to blank identifier
Sunday
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
)
In the process of using enumerated values, there is often a demand for output printing
fmt.Println(Sunday, Monday) // 1 2
However, the original result is not intuitive, and it can not reflect the meaning behind the enumerated values. We need to define the output for the Weekday object.
func (w Weekday) String() string {
return [...]string{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}[w-1]
}
In Go, we can bind the String() method for any custom type to print according to the format defined in the String() method.
func main() {
var day = Monday
switch day {
case Monday, Tuesday, Wednesday, Thursday, Friday:
fmt.Printf("Today is%s,come on. office worker", day)
case Saturday, Sunday:
fmt.Printf("Today is%s,have a good rest! office worker", day)
default:
fmt.Println("A day that doesn't exist")
}
}
results of enforcement
Today is Monday,come on. office worker
Insufficient implementation of Go enumeration
The above scheme seems to have implemented the enumeration function, but there are some problems.
First of all, since iota is based on int type, it means that any integer can be converted to enumeration type in the program (which is why we switch the case above) There will be a default branch in), but this is not what we want.
func main() {
fakeNum := 8
day := Weekday(fakeNum)
fmt.Println(day)
}
# go run main.go
%!v(PANIC=String method: runtime error: index out of range [7] with length 7)
The thoughtful reader will think that since int is not good, we can use string constants to represent enumeration values. But this scheme also has the above problems, and compared with using int comparison, it needs to pay additional performance cost when comparing strings.
In addition, we also have a very important demand for enumeration, that is, iteration. Corresponding to the Go loop expression, the expectation of enumeration iteration is this
for i, day := range Weekday {
...
}
But obviously, the current code scheme can not meet this demand.
summary
This paper discusses the current practice of Go enumerating through iota keyword, but this method does not realize the complete enumeration function. The proposal that enum keyword should be added to Go is put forward in the official issue 19814. Interested readers can check it in detail.
Do you have different views on the enumeration implementation in Go? Welcome to leave a message for discussion.
reference resources
proposal: spec: add typed enum support: https://github.com/golang/go/issues/19814