Go 如何实现“真正意义上”的枚举
枚举是一个强大的特性,拥有广泛的应用场景。然而,在 Go 语言中,却没有原生支持枚举。在本文中,我将用 Go 语言的实现枚举。
什么是枚举?
枚举是从字面含义来说,就是列举出有穷集合中的所有元素。像一周的表示就是一个有限集合,只有七种可能的取值,所以一周就可以视为一个枚举类型。一个枚举项包含一个索引值(key)和一个字符值(value)。
Key | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|
Enum | Sunday | Monday | Tuesday | Wednesday | Thursday | Friday | Saturday |
Value | “Sunday” | “Monday” | “Tuesday” | “Wednesday” | “Thursday” | “Friday” | “Saturday” |
使用Go实现枚举?
枚举基本实现
先来实现基本的枚举功能,我们要实现以下几点:
- 通过
type
关键字给int
类型起别名,达到自定义枚举类型的效果; - 通过
iota
关键字 + 自定义的类型赋值给常量,作为枚举项; - 实现
Index
方法返回枚举项的索引值,借助类型转换,将自定义类型转回 int 类型; - 实现
String
方法返回枚举项的字符值,Go 语言 Stringer 接口定义 String 方法,一个类型只要有 String 方法,我们就说它实现了 Stringer 接口,那么在格式化时就会调用 String 方法处理;
Stringer接口的定义如下:
type Stringer interface {
String() string
}
以实现“周”的枚举为例,具体代码实现如下:
package Weekday
// Weekday 自定义类型
type Weekday int
// 声明每个枚举项的索引值
const (
Sunday Weekday = iota + 1 // Index = 1
Monday // Index = 2
Tuesday // Index = 3
Wednesday // Index = 4
Thursday // Index = 5
Friday // Index = 6
Saturday // Index = 7
)
var weekdayStr = []string{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}
// String - 返回枚举项的索引值
func (w Weekday) String() string {
return weekdayStr[w-1]
}
// Index - 返回枚举项的字符值
func (w Weekday) Index() int {
return int(w)
}
那该如何使用?我们可以这样使用枚举。
func main() {
var sunday = Weekday.Sunday
fmt.Println(sunday) // Print : Sunday
fmt.Println(sunday.String()) // Print : Sunday
fmt.Println(sunday.Index()) // Print : 1
}
实现两个辅助函数
上面我们实现了枚举的基本功能,每个枚举值都有索引值
,都有字符值
。下面,为了让枚举更好用,我们在包内增加两个辅助函数:
Values
函数返回枚举的所有值;ExistOf
函数判断某值是否存在枚举值中;
实现代码如下:
package Weekday
......
// Values 返回枚举的所有值
func Values() []string {
return weekdayStr
}
// ExistOf 判断某值是否存在枚举值中
func ExistOf(str string) bool {
for _, v := range weekdayStr {
if v == str {
return true
}
}
return false
}
那该如何使用?我们可以这样使用这两个辅助函数。开发中常常会遇到判断入参是否合法的枚举值的场景,我们可以快速地使用 ExistOf
函数来实现应对。
func main() {
var sunday = Weekday.Sunday
fmt.Println(Weekday.Values())
// Print : [Sunday Monday Tuesday Wednesday Thursday Friday Saturday]
fmt.Println(Weekday.ExistOf("abc")) // Print : false
fmt.Println(Weekday.ExistOf("Monday")) // Print : true
}
完整代码
github.com/newbugcoder/learngo/tre...
package Weekday
// Weekday 自定义类型
type Weekday int
// 声明每个枚举项的索引值
const (
Sunday Weekday = iota + 1 // Index = 1
Monday // Index = 2
Tuesday // Index = 3
Wednesday // Index = 4
Thursday // Index = 5
Friday // Index = 6
Saturday // Index = 7
)
var weekdayStr = []string{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}
// ======== 枚举实现 ========
// String - 返回枚举项的索引值
func (w Weekday) String() string {
return weekdayStr[w-1]
}
// Index - 返回枚举项的字符值
func (w Weekday) Index() int {
return int(w)
}
// ======== 辅助函数 ========
// Values 返回枚举的所有值
func Values() []string {
return weekdayStr
}
// ExistOf 判断某值是否存在枚举值中
func ExistOf(str string) bool {
for _, v := range weekdayStr {
if v == str {
return true
}
}
return false
}
总结
本文我们先介绍了枚举的结构,然后使用 Go 语言实现了枚举的特性以及辅助函数。本文的实现不能算得上完美,有点瑕疵,即:一个包作为一个枚举,包的利用率不高。但使用上算是相对优雅,也提供Go语言实现枚举的一种思路,如果有更好的方案,欢迎探讨。
本作品采用《CC 协议》,转载必须注明作者和本文链接
:joy:你写个const呀,写个var不怕别人代码里篡改map么
weekdayStr
感觉用map
数据类型会更优雅