Golang中如何声明枚举类型?
Golang中如何声明枚举类型? 如何在Golang中声明类似Java的枚举:
enum WeekDay {
SATURDAY,
SUNDAY,
...
}
我找到了一种解决方案:
type WeekDay int
const (
Saturday WeekDay = 1
Sunday WeekDay = 2
)
func aFunc(WeekDay WeekDay) {
...
}
但问题在于,当需要声明参数时,我可以使用显式整数而不是Weekday:
aFunc(55)
如何限制在参数中传递整数?
提前感谢。
更多关于Golang中如何声明枚举类型?的实战教程也可以访问 https://www.itying.com/category-94-b0.html
6 回复
我很抱歉生气,但这只是因为 Go 语言的局限性。
我从未这样说过。我说的是"你不能",并展示了使用 iota 作为更符合语言习惯的方法,仅此而已。
引用 Hamed_Mostafaei:
如何限制在参数中传递整数?
你无法做到。
此外,更符合语言习惯的做法是使用 iota:
type WeekDay int
const (
Saturday WeekDay = iota
Sunday
Monday
Tuesday
// ...
}
一种(愚蠢的)实现方式是创建新类型并为其实现符合某个接口的方法
package weekday
// 创建新类型 weekday
type weekday string
// 为其实现某个方法
// 返回未导出的类型
func (w weekday) isWeekday() weekday {
return w
}
// 导出的接口
type Weekday interface {
isWeekday() weekday
}
const (
Monday = weekday("Monday")
Tuesday = weekday("Tuesday")
Wendsday = weekday("Wendsday")
Thursday = weekday("Thursday")
Friday = weekday("Friday")
Saturday = weekday("Saturday")
Sunday = weekday("Sunday")
)
使用此类型/接口时,必须经过严格操作才能为其分配随机值
package main
import (
"fmt"
"./weekday"
)
// 将接口用于参数
func print(w weekday.Weekday) {
fmt.Println("Day is", w)
}
func main() {
var d1 = weekday.Monday
var d2 = weekday.Tuesday
fmt.Println(d1, d2, d1 == d2, d1 == weekday.Monday)
print(d1)
}
输出结果
$ go run main.go
Monday Tuesday false true
Day is Monday
但这种方式相当笨拙且丑陋…
在Go语言中,没有内置的枚举类型,但可以通过类型定义和常量组来模拟枚举行为。要限制参数只能传递特定的枚举值,可以使用自定义类型并实现严格的类型检查。以下是改进方案:
package main
import "fmt"
// 定义WeekDay类型
type WeekDay int
// 声明枚举常量
const (
Saturday WeekDay = iota + 1 // 从1开始
Sunday
Monday
Tuesday
Wednesday
Thursday
Friday
)
// 验证函数,确保只接受有效的WeekDay值
func (d WeekDay) IsValid() bool {
switch d {
case Saturday, Sunday, Monday, Tuesday, Wednesday, Thursday, Friday:
return true
}
return false
}
// 业务函数,添加验证
func aFunc(day WeekDay) {
if !day.IsValid() {
panic("invalid WeekDay value")
}
fmt.Printf("Day value: %d\n", day)
}
// 安全构造器模式
func NewWeekDay(value int) (WeekDay, error) {
day := WeekDay(value)
if !day.IsValid() {
return 0, fmt.Errorf("invalid WeekDay value: %d", value)
}
return day, nil
}
func main() {
// 正确用法
aFunc(Saturday) // 输出: Day value: 1
aFunc(Sunday) // 输出: Day value: 2
// 错误用法示例(编译通过但运行时报错)
// aFunc(55) // 运行时panic: invalid WeekDay value
// 使用安全构造器
if day, err := NewWeekDay(1); err == nil {
aFunc(day) // 输出: Day value: 1
}
if _, err := NewWeekDay(55); err != nil {
fmt.Println(err) // 输出: invalid WeekDay value: 55
}
}
更严格的方案使用未导出类型和构造函数:
package main
import "fmt"
// 未导出类型,外部无法直接创建
type weekDay int
// 枚举常量
const (
saturday weekDay = iota + 1
sunday
monday
// ... 其他天
)
// 导出变量提供访问
var (
Saturday = saturday
Sunday = sunday
Monday = monday
)
// 只能通过预定义值调用
func aFunc(day weekDay) {
fmt.Printf("Day value: %d\n", day)
}
func main() {
aFunc(Saturday) // 正确
aFunc(Sunday) // 正确
// aFunc(55) // 编译错误:cannot use 55 (type int) as type weekDay
}
第一种方案允许类型转换但提供运行时验证,第二种方案通过未导出类型在编译时阻止非法值。选择取决于具体需求:需要灵活性使用第一种,需要编译时安全使用第二种。

