我在golang中使用iota定义了以下类型。
type StatusType int
const (
PENDING StatusType = iota
APPROVED
REJECTED
)
我想将REST-API中传递的值限制为StatusType。这样的值不应超过0,1,2。
只是不要导出StatusType
(假设你在包'status
'中定义它)。
这跟随“What is an idiomatic way of representing enums in Go?”:
type statusType int
const (
PENDING statusType = iota
APPROVED
REJECTED
)
type StatusTyper interface {
StatusType() statusType
}
func(st statusType) StatusType() statusType {
return st
}
然后,任何外部包都会将StatusType
类变量称为status.PENDING
,status.APPROVED
或status.REJECTED
。
(只有三个statusType
实现了StatusTyper
接口.Caveat applies。)
我这样做: 首先创建一个名为“StatusType”的包(在名为StatusType的文件夹中): filename:$ GOPATH / enum / StatusType / StatusType.go
package StatusType
type Int int
const (
Pending Int = iota
Approved
Rejected
end
)
func IsValid(value int) bool {
return value < int(end)
}
并使用这样($ GOPATH / enum / main.go):
package main
import (
"enum/StatusType"
"fmt"
)
func Test(enum StatusType.Int) {
fmt.Println(enum) //1
}
func main() {
Test(StatusType.Approved)
fmt.Println(StatusType.IsValid(1)) //true
fmt.Println(StatusType.IsValid(10)) //false
}
StatusType包只会导出您需要的内容,因此无需检查iota const范围。 如果您要检查,请使用:StatusType.IsValid() 关于StatusType包的好处是: 当你想要StatusType类型的函数参数时,使用StatusType.Int,它显示它是int类型的枚举。 喜欢:
Test(StatusType.Approved)
假设您希望无效的JSON有效负载失败,请实现Unmarshaler接口:https://play.golang.org/p/zuchzQ0vmo
使用github.com/alvaroloes/enumer生成
package main
import "fmt"
//go:generate enumer -type=StatusType
type StatusType int
const (
PENDING StatusType = iota
APPROVED
REJECTED
)
func main() {
fmt.Println(StatusType(0).IsAStatusType()) // true
fmt.Println(StatusType(1).IsAStatusType()) // true
fmt.Println(StatusType(2).IsAStatusType()) // true
fmt.Println(StatusType(3).IsAStatusType()) // false
}
iota只是一个编译器。代码相当于:
const PENDING int = 0
const APPROVED int = 1
...
因此,设计一个函数CheckValid()来确定该值是否在给定值中。如果const在连续范围内,您可以使用user6169399的方法。或者你可以简单地定义一个var map [YOUR_TYPE_HERE] bool来验证。
func (t YOUR_TYPE) CheckValid(){
if _, ok:=map[t];ok return true
else return false
}
如果没有地图https://play.golang.org/p/eKW_KPshx7b,还有另外两种方法可以做到这一点
package main
import (
"errors"
"log"
)
type StatusType int
const (
PENDING StatusType = iota
APPROVED
REJECTED
)
func Validate(val int) (bool, error) {
if v := StatusType(val); v > REJECTED || v < PENDING {
return false, errors.New("invalid StatusType")
}
return true, nil
}
func (t StatusType) Validate() (bool, error) {
if t > REJECTED || t < PENDING {
return false, errors.New("invalid StatusType")
}
return true, nil
}
func main() {
log.Print(Validate(-1))
log.Print(Validate(0))
log.Print(Validate(1))
log.Print(Validate(3))
log.Print(StatusType(-1).Validate())
log.Print(StatusType(1).Validate())
log.Print(StatusType(10).Validate())
}
我也在努力解决这个问题,因为我真的想找到一些简单的方法来检查传入的值是否在正确的范围内。我想出的诀窍如下:
type StatusType int
const (
PENDING StatusType = iota
APPROVED
REJECTED
)
func (st StatusType) String() string {
switch st {
case PENDING:
return "STATUS:PENDING"
case APPROVED:
return "STATUS:APPROVED"
case REJECTED:
return "STATUS:REJECTED"
defaut:
return "INVALID"
}
}
func (st StatusType) IsValid() bool {
return st.String() != "INVALID"
}
因为我经常需要将枚举值转换为一些有意义的表示,所以我倾向于将String()
添加到枚举类型中。案例涵盖所有合法值,而默认路径捕获值无效的情况。
简单地说,要检查某个值是否有效,请将其字符串表示与默认情况进行比较。
我的解决方案的一个好处是,如果将来添加另一个枚举值,我们只需要在String()
方法中添加一个案例。 IsValid()
方法仍然有效。
另一个好处是,在值的范围不连续的情况下,我的解决方案也有效。如下定义:
const (
PENDING StatusType = 1001
APPROVED = 1003
REJECTED = 1005
)