Go Enumerations

From NovaOrdis Knowledge Base
Revision as of 20:30, 13 September 2024 by Ovidiu (talk | contribs) (→‎Default Enum Value)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

External

Internal

Overview

Go does not have formal enums, but the language allows for sets of related, yet distinct int constants. They represent a property that has several distinct possible int values, like the days of the weeks or the months of the year. To make the enumeration constants visible outside the package, they need to start with a capital letter.

These auto-incrementing int constants are declared using a special syntax involving the const keyword, parentheses, a type and the pre-declared constant iota:

type SomeType int

const (
  UndefinedEnum SomeType = iota
  EnumOne
  EnumTwo
  ...
)

This article explains how iota is used to generate values for enumeration members:

How Does the Compiler Assign Values to iota

The short story is that iota takes the zero-based index of the constant declaration it is used for, as it appears in the const() list. The first declaration is the explicit one, the subsequent ones are implicit.

Example:

type DayOfTheWeek int
const (
  UNDEFINED_DAY DayOfTheWeek = iota // iota is equal with 0, which is the zero value for int
  MON 
  TUE
  WED
  THU
  FRI
  SAT
  SUN
)

Only the first constant in the series explicitly declares its type and an expression involving iota. The subsequent declaration assume the same type and expression.

The simplest expression involving iota is iota itself, but more complex expressions can be used. Different declarations for enums part of the same set can use different iota expressions, and for those enum declaration that do not have an explicit declaration, the last one applies.

type ByteSize float64

const (
	UNDEFINED ByteSize = iota             // assign the first value, which is zero, and the zero value for it, to an 'UNDEFINED' enum element
	KB        ByteSize = 1 << (10 * iota) // gets 1024
	MB                                    // 1 << (10 * iota) applies, MB gets 1048576
	GB                                    // ...
	TB
	PB
	EB
	ZB
	YB
)

Default Enum Value

It is a good practice to declare the first enum element in the series as the default value for the enum set, and explicitly name it as such.

If there is an obvious candidate for the default value, use that name.

Otherwise, use "Undefined", and make sure its value is the zero value for the enum's type. In case of int, the zero-value is 0.

type SomeType int

const (
	Undefined SomeType = iota // gets 0, as the zero-value for int
	ElemOne
	ElemTwo
)

Naming Convention

Is it good practice to include the type name in the enum element name?

type QuotaType int

const (
	UndefinedQuotaType QuotaType = iota
	AbsoluteQuotaType
	FractionalQuotaType
)

String Representation

const enums can take advantage go the possibility of attaching a String() method to any type, including the enum type, to provide a string representation.

type DayOfTheWeek int

const (
	MON DayOfTheWeek = iota
	TUE
	WED
	THU
	FRI
	SAT
	SUN
)

var dayOfTheWeekToString = []string{
	"Monday",
	"Tuesday",
	"Wednesday",
	"Thursday",
	"Friday",
	"Saturday",
	"Sunday",
}

func (s DayOfTheWeek) String() string {
	return dayOfTheWeekToString[s]
}

func StringToDayOfTheWeek(s string) DayOfTheWeek {
	for i, v := range dayOfTheWeekToString {
		if s == v {
			return DayOfTheWeek(i)
		}
	}
	return DayOfTheWeek(-1)
}