枚举(enumeration)
Golang 语言并没有提供enum的定义,我们可以使用const来模拟枚举类型。
type PolicyType int32
const (
Policy_MIN PolicyType = 0
Policy_MAX PolicyType = 1
Policy_MID PolicyType = 2
Policy_AVG PolicyType = 3
)
这里定义了一个新的类型PolicyType,并且定义了4个常量(Policy_MIN, Policy_MAX, Policy_MID, Policy_AVG),类型是PolicyType。
使用举例
func foo(p PolicyType) {
fmt.Printf("enum value: %v\n", p)
}
func main() {
foo(Policy_MAX)
}
iota
- The
iota
keyword represents successive integer constants 0, 1, 2,… - It resets to 0 whenever the word
const
appears in the source code, - and increments after each const specification.
const (
C0 = iota
C1 = iota
C2 = iota
)
fmt.Println(C0, C1, C2) // "0 1 2"
This can be simplified to
const (
C0 = iota
C1
C2
)
Here we rely on the fact that expressions are implicitly repeated in a parenthesized const declaration – this indicates a repetition of the preceding expression and its type.
Start from one
To start a list of constants at 1 instead of 0, you can use iota
in an arithmetic expression.
const (
C1 = iota + 1
C2
C3
)
fmt.Println(C1, C2, C3) // "1 2 3"
Or
const (
_ int = iota // Skip the first value of 0
Foo // Foo = 1
Bar // Bar = 2
_
_
Bin // Bin = 5
// Using a comment or a blank line will not increment the iota value
Baz // Baz = 6
)
Skip value
You can use the blank identifier to skip a value in a list of constants.
const (
C1 = iota + 1
_
C3
C4
)
fmt.Println(C1, C3, C4) // "1 3 4"
Complete enum type with strings [best practice]
Here’s an idiomatic way to implement an enumerated type:
- create a new integer type,
- list its values using
iota
, - give the type a
String
function.
type Direction int
const (
North Direction = iota
East
South
West
)
func (d Direction) String() string {
return [...]string{"North", "East", "South", "West"}[d]
}
In use:
var d Direction = North
fmt.Print(d)
switch d {
case North:
fmt.Println(" goes up.")
case South:
fmt.Println(" goes down.")
default:
fmt.Println(" stays put.")
}
// Output: North goes up.
Bitmask
const (
read = 1 << iota // 00000001 = 1
write // 00000010 = 2
remove // 00000100 = 4
// admin will have all of the permissions
admin = read | write | remove
)
By definition, multiple uses of iota
in the same ConstSpec all have the same value:
const (
bit0, mask0 = 1 << iota, 1<<iota - 1 // bit0 == 1, mask0 == 0 (iota == 0)
bit1, mask1 // bit1 == 2, mask1 == 1 (iota == 1)
_, _ // (iota == 2, unused)
bit3, mask3 // bit3 == 8, mask3 == 7 (iota == 3)
)
Misc
const (
a = 1 << iota // a == 1 (iota == 0)
b = 1 << iota // b == 2 (iota == 1)
c = 3 // c == 3 (iota == 2, unused)
d = 1 << iota // d == 8 (iota == 3)
)
const (
u = iota * 42 // u == 0 (untyped integer constant)
v float64 = iota * 42 // v == 42.0 (float64 constant)
w = iota * 42 // w == 84 (untyped integer constant)
)
const x = iota // x == 0
const y = iota // y == 0
type ByteSize float64
const (
_ = iota // ignore first value by assigning to blank identifier
KB ByteSize = 1 << (10 * iota)
MB
GB
TB
PB
EB
ZB
YB
)
Naming convention
The standard naming convention is to use mixed caps also for constants.
For example, an exported constant is NorthWest
, not NORTH_WEST
.
Creating names automatically
# install the stringer tool
go get -u -a golang.org/x/tools/cmd/stringer# grab the code from here
# weekday.go
package main
import (
"fmt"
)
// Declare a new type named Weekday which will unify our enum values
// It has an underlying type of unsigned integer (uint).
type Weekday int
// Declare typed constants each with type of Weekday
const (
Sunday Weekday = 0
Monday Weekday = 1
Tuesday Weekday = 2
Wednesday Weekday = 3
Thursday Weekday = 4
Friday Weekday = 5
Saturday Weekday = 6
)
// String returns the name of the day
func (day Weekday) String() string {
names := [...]string{"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"}
return names[day]
}
// Weekend return true for a weekend day
func (day Weekday) Weekend() bool {
switch day {
case Sunday, Saturday:
return true
default:
return false
}
}
func main() {
// Which day it is? Sunday
fmt.Printf("Which day it is? %s\n", Sunday)
// Is Saturday a weekend day? true
fmt.Printf("Is Saturday a weekend day? %t\n", Saturday.Weekend())
// Is Monday a weekend day? false
fmt.Printf("Is Monday a weekend day? %t\n", Monday.Weekend())
}
# enum names automatically
stringer -type Weekday weekdays.go
Reference
- https://golang.org/ref/spec
- https://github.com/golang/go/wiki/Iota
- https://yourbasic.org/golang/iota/
- https://blog.learngoprogramming.com/golang-const-type-enums-iota-bc4befd096d3