go2020년 12월 20일5 min read

Enum Constants in Go (Enums in Go)

How to declare enum-like constants in Go using the iota keyword, with examples for ByteSize, bitwise flags, and iterating enums.

FFrank Advenoh
#golang#enums#iota

1. Introduction

In Go, the Enums type provided by Java does not exist. However, in Go too, you can easily declare and use enum-like constant values using iota.

The iota keyword is a predefined identifier that can be used in a const declaration and represents the successive integer constants 0, 1, 2, .... Let's learn how to use it through examples.

//#builtin.go
// iota is a predeclared identifier representing the untyped integer ordinal
// number of the current const specification in a (usually parenthesized)
// const declaration. It is zero-indexed.
const iota = 0 // Untyped int.

2. iota Examples

2.1 Basic Example

The starting value of iota is 0, and from then on it's declared with a value incremented by +1.

func Example_iota_basic() {
  const (
    c0 = iota
    c1 = iota
    c2 = iota
  )

  fmt.Println(c0, c1, c2)
  //Output:
  //0 1 2
}

Instead of using the iota keyword every time, if you declare it just once, successive values are declared for the remaining variables.

func Example_iota_basic2() {
	const (
		c0 = iota
		c1
		c2
	)

	fmt.Println(c0, c1, c2)
	//Output:
	//0 1 2
}

2.2 Changing the Starting Value

You can also easily change the starting value.

func Example_iota_change_start_value() {
	const (
		c0 = iota + 5
		c1
		c2
	)

	fmt.Println(c0, c1, c2)
	//Output:
	//5 6 7
}

2.3 Skipping Intermediate Values

2.3.1 How to Skip a Single Value

To skip an intermediate value, use a blank identifier to skip it.


func Example_iota_intermediate_value_skipped() {
	const (
		c0 = iota + 1
		_
		c1
		c2
	)

	fmt.Println(c0, c1, c2)
	//Output:
	//1 3 4
}

2.4.2 How to Skip One or More Values

Let's learn how to skip one or more values and declare constant values, as below.

1, 2, 100, 101, 500, 501

2.4.2.1 Calculating the Values to Jump Directly

You can declare the values of the sections to skip by calculating them directly.

func Example_iota_intermediate_value_specified_differently() {
	//calculate manually
	const (
		c0 = iota + 1   //1
		c1              //2
		c2 = iota + 98  //100
		c3              //101
		c4 = iota + 496 //500
		c5              //501
	)

	fmt.Println(c0, c1, c2, c3, c4, c5)
	//Output:
	//1 2 100 101 500 501
}

2.4.2.2 Declaring by Splitting into const Groups

Rather than directly calculating the sections to jump, splitting the declaration into multiple groups as below makes it a bit easier to declare.

func Example_iota_intermediate_value_specified_differently2() {
	//calculate manually
	const (
		c0 = iota + 1 //1
		c1            //2
	)
	const (
		c2 = iota + 100 //100
		c3              //101
	)
	const (
		c4 = iota + 500 //500
		c5              //501
	)

	fmt.Println(c0, c1, c2, c3, c4, c5)
	//Output:
	//1 2 100 101 500 501
}

3. A Collection of Enum Examples

These are examples that can be used in an enum style.

3.1 Declaring ByteSize Constant Values

Declare data units as below. If you declare only the KB unit, the remaining units MB, GB... are also easily declared.

func Example_iota_BYTE_example() {
	type ByteSize float64

	const (
		_           = iota             // ignore the first one with a blank identifier
		KB ByteSize = 1 << (10 * iota) //2^(10*1) = 1024
		MB                             //2^(10*2) = 1,048,576
		GB
		TB
		PB
		EB
		ZB
		YB
	)
	var fileSize ByteSize = 4000000000 //4 GB
	fmt.Printf("%.2f GB", fileSize/GB)
	//Output:
	//3.73 GB
}

3.2 Checking Flag Values or Options with Bitwise Operations

This is an example of applying multiple options or flags through bitwise operations and checking whether they're applied with an AND operation. In this example, we assign multiple roles to a user and check the roles.


func Example_iota_bitwise_role_example() {
	const (
		isAdmin          = 1 << iota //1
		isHeadquarters               //10
		canSeeFinancials             //100

		canSeeAfrica       //1000
		canSeeAsia         //10000
		canSeeEurope       //100000
		canSeeNorthAmerica //1000000
		canSeeSouthAmerica //10000000
	)

	var myRoles byte = isAdmin | canSeeFinancials | canSeeEurope
	fmt.Printf("%b\n", myRoles)
	fmt.Printf("is admin? %v\n", isAdmin & myRoles == isAdmin)
	fmt.Printf("is HQ? %v\n", isHeadquarters & myRoles == isHeadquarters)
	//Output:
	//100101
	//is admin? true
	//is HQ? false
}

3.3 Iterating Over Declared Enums

When declaring constants, use the last value to iterate.

type WeekDay int

func Example_iterate_weekdays() {
	const (
		Sunday WeekDay = iota
		Monday
		Tuesday
		Wednesday
		Thursday
		Friday
		Saturday
		numberOfDays
	)

	for day := WeekDay(0); day < numberOfDays; day++ {
		fmt.Print(" ", day)
	}
	fmt.Println("")
	//Output:
	//Sunday Monday Tuesday Wednesday Thursday Friday Saturday
}

func (d WeekDay) String() string {
	var weekDays = [...]string{
		"Sunday",
		"Monday",
		"Tuesday",
		"Wednesday",
		"Thursday",
		"Friday",
		"Saturday",
	}

	return weekDays[int(d)%len(weekDays)]
}

4. Conclusion

We looked at how to declare in an enum style in the Go language. We used the iota keyword to easily declare constant values and saw various examples too. The code written in this post can be found on github.

5. References

관련 글