Is there enumeration in Go?

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

Keywords: Go

Added by Robert Elsdon on Tue, 30 Nov 2021 06:17:17 +0200