我在golang中使用iota定义了以下类型。
type StatusType int
const (
PENDING StatusType = iota
APPROVED
REJECTED
)
我想将REST-API中传递的值限制为StatusType。这样的值不应超过0,1,2。
答案 0 :(得分:8)
只是不要导出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。)
答案 1 :(得分:8)
我这样做:
首先创建一个名为“StatusType”的包(在名为StatusType的文件夹中):
filename:$ GOPATH / enum / StatusType / StatusType.go
-1
并像这样使用($ GOPATH / enum / main.go):
package StatusType
type Int int
const (
Pending Int = iota
Approved
Rejected
end
)
func IsValid(value int) bool {
return value < int(end)
}
StatusType包只会导出您需要的内容,因此无需检查iota const范围
如果您想检查,请使用:StatusType.IsValid()
关于StatusType包的好处是:
当你想要StatusType类型的函数参数时,使用StatusType.Int,它显示它是int类型的枚举
像:
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
}
答案 2 :(得分:3)
假设您希望无效的JSON有效负载失败,请实施Unmarshaler接口:https://play.golang.org/p/zuchzQ0vmo
答案 3 :(得分:0)
使用go 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
}
答案 4 :(得分:0)
iota仅仅是一个编译器。该代码等效于:
const PENDING int = 0
const APPROVED int = 1
...
因此,要设计一个函数CheckValid()来确定该值是否在给定值中。 如果您的const处于连续范围内,则可以使用user6169399的方法。 或者,您可以简单地定义一个变量映射[YOUR_TYPE_HERE] bool进行验证。
func (t YOUR_TYPE) CheckValid(){
if _, ok:=map[t];ok return true
else return false
}
答案 5 :(得分:0)
这里有另外两种无需地图即可完成此操作的方法 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())
}
答案 6 :(得分:-1)
我也很努力地解决这个问题,因为我真的想找到一种简单的方法来检查传入的值是否在正确的范围内。我想到的技巧如下:
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
)