Cookies management by TermsFeed Cookie Consent

πŸ–οΈ Declare enum in Go

introduction enum iota const

In Go, there is no enum data type known from languages such as C++, Java, or Python. However, this does not mean that enums cannot be created. If you declare constants of custom type and some helper methods, you get a structure very similar to enum in other programming languages.

See the example below to check how to declare enum in Go.

In the example, we use constants declaration with iota. Check our tutorial on how to use iota in Go.

package main

import (
	"fmt"
)

type Season int

const (
	Spring Season = iota + 1
	Summer
	Autumn
	Winter
)

func (s Season) String() string {
	seasons := [...]string{"spring", "summer", "autumn", "winter"}
	if s < Spring || s > Winter {
		return fmt.Sprintf("Season(%d)", int(s))
	}
	return seasons[s-1]
}

func (s Season) IsValid() bool {
	switch s {
	case Spring, Summer, Autumn, Winter:
		return true
	}
	return false
}

func main() {
	mySeasons := []Season{Spring, Summer, Autumn, Winter, 6}
	for _, s := range mySeasons {
		fmt.Printf("season: %s, is valid: %t\n", s, s.IsValid())
	}
}

Output:

season: spring, is valid: true
season: summer, is valid: true
season: autumn, is valid: true
season: winter, is valid: true
season: Season(6), is valid: false

How it works

  1. Declare custom type and elements of our enum
    type Season int
    
    const (
    	Spring Season = iota + 1
    	Summer
    	Autumn
    	Winter
    )
    

    As a first step, we declare new integer type Season and create successive constant values using the iota keyword.

    Why do we use int type instead of string?

    Constants are usually used to compare to a variable, e.g.

    if Spring != season { 
        // do something 
    }
    

    and often we do not need their specific values, just the fact that the constant and the variable are different. In such a case comparing two int values is faster than comparing two strings. Constants of type int also take less memory space.

    Why do we declare the custom type Season instead of using untyped constants?

    A custom type protects against passing invalid values already at the compilation stage. If we declared seasons as untyped constants, the code below of assigning invalid season value 6 to the variable would execute without any error:

    var d int = 6
    season := Spring
    season = d
    

    When using Season type, to make this code run without any error, you need to explicitly convert the d variable, so it is not possible to do it by accident:

    var d int = 6
    season := Spring
    season = Season(d)
    

    Also, a custom type of enum makes the code cleaner. For example, declaring the function

    func foo(s Season)
    

    you immediately see that the function requires season as an argument, and in the case of

    func foo(s int)
    

    you only know that it needs an integer argument, without any semantic meaning. Thanks to the custom types we also can add methods to the enum elements like String() and IsValid().

  2. Create String() method
    func (s Season) String() string {
    	seasons := [...]string{"spring", "summer", "autumn", "winter"}
    	if s < Spring || s > Winter {
    		return fmt.Sprintf("Season(%d)", int(s))
    	}
    	return seasons[s-1]
    }
    

    String() method adds the ability to print Season constants as a string rather than an int, so for the statement fmt.Println(Spring) we get spring instead of 1. For variables outside the range Spring..Winter, we print Season(X), where X is an integer value of the Season type variable.

  3. Create IsValid() method
    func (s Season) IsValid() bool {
    	switch s {
    	case Spring, Summer, Autumn, Winter:
    		return true
    	}
    	return false
    }
    

    IsValid() is a helper method that validates whether the Season type variable is one of the values Spring, Summer, Autumn, or Winter. This function should always be called for user input, to verify that the user has not passed an invalid value of the enum.

  4. main() function
    func main() {
    	mySeasons := []Season{Spring, Summer, Autumn, Winter, 6}
    	for _, s := range mySeasons {
    		fmt.Printf("season: %s, is valid: %t\n", s, s.IsValid())
    	}
    }
    

    The main() function presents what you get when you use the String() and IsValid() methods for defined values of Season constants as well as values out of range.


Thank you for being on our site 😊. If you like our tutorials and examples, please consider supporting us with a cup of coffee and we'll turn it into more great Go examples.

Have a great day!

Buy Me A Coffee

🧐 iota in Go - how to use?

Learn how to use iota keyword in constants declaration
introduction iota const

♾️ Infinite loop in Go

Learn how to define a “while true” loop
introduction loop

πŸ“” Convert a struct to io.Reader in Go

Learn how to convert a struct to io.Reader and send it as an HTTP POST request body
introduction http