有没有一种方法可以迭代常量作为枚举使用?

huangapple go评论82阅读模式
英文:

is there a way to iterate over constant used as enum

问题

我正在尝试在golang中使用枚举,代码如下。我正在努力寻找一种简单的方法来迭代常量值列表。在golang中,常用的做法是如何迭代用作枚举的常量值。谢谢!

type DayOfWeek int
const(
       Monday DayOfWeek = iota
       Tuesday
       Wednesday
       Thursday
       Friday
       Saturday
       Sunday
      )

在Java中,我们可以按如下方式进行迭代。

public enum DayOfWeek {
    MONDAY, 
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY
}

for (DayOfWeek day: DayOfWeek.values()) {
   // 代码逻辑
}
英文:

I am trying to use enum in golang as below. I am struggling to find a easy way to iterate over the list of constant values. What are common practice in golang to iterate over constant values used as enum. Thanks!

type DayOfWeek int
const(
       Monday DayOfWeek = iota
       Tuesday
       Wednesday
       Thursday
       Friday
       Saturday
       Sunday
      )

In Java, we can iterate as below.

public enum DayOfWeek {
    MONDAY, 
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY
}

for (DayOfWeek day: DayOfWeek.values()) {
   // code logic
}

答案1

得分: 28

在运行时,除非你明确定义一个列出这些值/实例的切片,否则没有直接的方法来枚举命名类型的值/实例,无论是变量还是常量。这取决于枚举类型的定义者或用户。

为了能够在运行时动态生成这个列表,例如通过反射,链接器必须保留所有包中定义的符号,就像Java一样。golang-nuts小组讨论了这个问题,涉及从包中导出的名称和函数,这是包常量定义的超集。https://groups.google.com/forum/#!topic/golang-nuts/M0ORoEU115o

如果只有在程序中引用了这个列表,语言可以包含用于在编译时生成这个列表的语法糖。然而,迭代顺序应该是什么呢?如果你的一周从星期一开始,我定义的列表就不太有用;你将不得不定义自己的切片来遍历从星期一到星期日的日期。

英文:

There is no direct way to enumerate the values/instances of named type at runtime, whether variables or constants, unless you specifically define a slice that lists them. This is left up to the definer or the user of the enumeration type.

package main

import (
    "fmt"
    "time"
)

var Weekdays = []time.Weekday{
    time.Sunday,
    time.Monday,
    time.Tuesday,
    time.Wednesday,
    time.Thursday,
    time.Friday,
    time.Saturday,
}

func main() {
    for _, day := range Weekdays {
            fmt.Println(day)
    }
}

In order be able to generate this list dynamically at runtime, e.g. via reflection, the linker would have to retain all the symbols defined in all packages, like Java does. The golang-nuts group discussed this, regarding names and functions exported from a package, a superset of package constant definitions. https://groups.google.com/forum/#!topic/golang-nuts/M0ORoEU115o

It would be possible for the language to include syntactic sugar for generating this list at compile time if and only if it were referenced by the program. What should the iteration order be, though? If your week starts on Monday the list I defined is not very helpful; you will have to define your own slice to range through the days from Monday to Sunday.

答案2

得分: 1

你可以在不使用反射的情况下完成这个操作。

首先,在编译时使用go generate执行Go工具Stringer。这将创建一个名为[filename]_string.go的文件,其中包含一个名为_[structname]_map的枚举值映射,将枚举变量名作为字符串进行引用。这个映射是私有的,所以只需在包初始化时将其赋值给一个公共映射。

var EnumMap map[Enum]string

func init() {
	EnumMap = _Enum_map
}

type Enum uint

//go:generate go run golang.org/x/tools/cmd/stringer -type=Enum

const (
	One Enum = iota
    Two
)

然后,你可以简单地遍历映射的键。

英文:

You can do that without reflection.

First execute the Go tools Stringer at compile time using go generate. This creates a file [filename]_string.go which contains a map _[structname]_map of enum values referencing enum variable names as strings. This map is private, so simply assign it to a public map upon package initialization.

var EnumMap map[Enum]string

func init() {
	EnumMap = _Enum_map
}

type Enum uint

//go:generate go run golang.org/x/tools/cmd/stringer -type=Enum

const (
	One Enum = iota
    Two
)

Then you can simply loop over the keys of the map.

答案3

得分: 1

@davec的评论很好。当计数递增1时,这个方法非常有效。

你可以使用一个简单的循环,例如:for d := Monday; d <= Sunday; d++ {}

我有一个按位跳跃的常量(1、2、4、8、16等):

const (
Approved = 1 << iota
AlreadyApproved
NotApproved
OldTicket
Unknown
)

我避免使用range,而是使用左移一位来遍历我的常量:

var score Bits
score = Set(score, AlreadyApproved)

for i := Approved; i < Unknown; i = i << 1 {
fmt.Println(i)
}

输出:

1
2
4
8
16

英文:

The comment from @davec was great. This works perfect when you have a count that increments by one.

You could either do a simple loop such as for d := Monday; d &lt;= Sunday; d++ {}

I had constant that jumped in bits (1,2,4,8,16 etc):

const (
	Approved = 1 &lt;&lt; iota
	AlreadyApproved
	NotApproved
	OldTicket
	Unknown
)

I avoided range and did a left shift one to move through my constant:

var score Bits
score = Set(score, AlreadyApproved)

for i := Approved; i &lt; Unknown; i = i &lt;&lt; 1 {
	fmt.Println(i)
}

Output:

1
2
4
8
16

答案4

得分: 1

使用stringer是可取的,它可以帮助您使用代码生成器保持代码库的最新状态。不幸的是,stringer并不总是生成映射。

对于任何有兴趣继续使用go生成器的人,我编写了一个名为enumall的小型代码生成器。它为每个提供的类型生成一个文件,其中包含保存给定类型的所有值的变量。

通过向您的代码添加代码生成器注释来使用它,就像这样:

//go:generate go run github.com/tomaspavlic/enumall@latest -type=Season

type Season uint8

const (
    Spring Season = 1 << iota
    Summer
    Autumn
    Winter
)

您可以在这里找到更多信息:https://github.com/tomaspavlic/enumall

英文:

Using stringer is preferable it can help you keep your codebase up to date using code generators. Unfortunately stringer does not always generate the map.

For anyone interested in keep using go generators for this purpose I wrote a small code generator called enumall. It produces a file for each provided type with variable holding all values for given type.

Use it by adding code generator comment to your code like this:

//go:generate go run github.com/tomaspavlic/enumall@latest -type=Season

type Season uint8

const (
    Spring Season = 1 &lt;&lt; iota
    Summer
    Autumn
    Winter
)

You can find more information here: https://github.com/tomaspavlic/enumall

答案5

得分: 0

for i := 0; i <= int(Sunday); i++ {
    fmt.Println(DayOfWeek(i))
}
for i := 0; i <= int(星期日); i++ {
    fmt.Println(星期几(i))
}
英文:
for i := 0; i &lt;= int(Sunday); i++ {
    fmt.Println(DayOfWeek(i))
}

huangapple
  • 本文由 发表于 2015年10月18日 00:44:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/33189060.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定