如何在Golang中检查一个值是否为iota常量类型?

16

我在 Golang 中使用 iota 定义了以下类型。

type StatusType int

const (
    PENDING StatusType = iota
    APPROVED
    REJECTED
)

我希望限制在REST API中传递的值为StatusType。这样,该值不应超过0、1、2。


3
与你的问题无关的细节,但是常量不应该使用大写字母(C语言风格)。它是待处理/已批准/已拒绝。 - basgys
可能是Golang:创建常量类型并限制类型的值的重复问题。 - icza
6个回答

12

我是这样做的:
首先创建一个名为"StatusType"的包(在名为StatusType的文件夹中):
文件名:$GOPATH/enum/StatusType/StatusType.go


首先创建一个名为“StatusType”的包(在名为StatusType的文件夹中):
文件名:$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)

4
我认为-1会被视为有效。 - makapuf

9

简单来说,如果你在'status'包中定义了StatusType,那么就不要导出它。

这个建议遵循自"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.PENDINGstatus.APPROVEDstatus.REJECTED
(这三种statusType是实现StatusTyper接口的唯一选项。 注意事项。)

1
StatusType 变为未公开的并使用接口是不够的。请参见我在 Golang: Creating a Constant Type and Restricting the Type's Values 中提出的一个小技巧,它允许实现即使具有未公开方法的接口。事实上,没有任何常量类型可以以这种方式受限制。 - icza

4

1

这里有另外两种不使用map的正确方法: 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())
}

如果有人决定在“REJECTED”之后放入另一个值,怎么办? - Avishay28

1

使用go generate和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
}

0

iota 只是编译器的一个东西。代码等同于:

const PENDING int = 0
const APPROVED int = 1
...

设计一个名为CheckValid()的函数,以确定该值是否在给定的值之间。如果您的常量处于连续范围内,则可以使用user6169399的方法。或者,您可以简单地定义一个名为map[YOUR_TYPE_HERE]bool的变量来进行验证。
func (t YOUR_TYPE) CheckValid(){
    if _, ok:=map[t];ok return true
    else return false
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接