【问题标题】:How to get all constants of a type in Go如何在 Go 中获取一个类型的所有常量
【发布时间】:2018-02-03 22:24:26
【问题描述】:

这是一个例子:

package main

type State int

const (
    Created State = iota
    Modified
    Deleted
)

func main() {
    // Some code here where I need the list
    // of all available constants of this type.
}

这个用例是创建一个有限状态机 (FSM)。能够获取所有常量将有助于我编写测试用例,以确保每个新值在 FSM 映射中都有对应的条目。

【问题讨论】:

  • 我认为你的术语有点不对劲。 go 中没有课程。或许更好的表述是,“获取给定类型包中的所有常量”?
  • 唯一想到的就是让它们在map[string]interface{}[]interface{} 中保持最新。
  • 实际上,在内心深处,你根本无法以任何方式做到这一点。 go 中的常量是无类型的。当你以任何方式使用它们时,它们就会被赋予一个类型。如果您可以牺牲它们的无类型性,其中一些建议将起作用。见blog.golang.org/constants。我猜您已经为它们分配了一个类型 State,所以这没什么大不了的,但需要注意一般情况。
  • @IamLearning 您可以聚合有类型或无类型的常量,还可以使用go/ast 及其相关包计算常量表达式。这是一项相当艰巨的工作,因此除非您有大量无法维护的情况需要此操作,否则我建议您按照@captncraig 的答案中的建议手动进行。
  • @RayfenWindspear 这不是真的。正如您链接到的博客文章所示,有类型化的常量,并且问题示例中的那些是类型化的(类型State 在常量声明中指定)。也没有理由将它们放入 []interface{} - 他们可以放入 []State 并保持类型安全。

标签: go fsm


【解决方案1】:

如果你的常量都是有序的,你可以使用这个:

type T int

const (
    TA T = iota
    TB
    TC
    NumT
)

func AllTs() []T {
    ts := make([]T, NumT)
    for i := 0; i < int(NumT); i++ {
        ts[i] = T(i)
    }
    return ts
}

您还可以将输出缓存在例如init()。这仅在所有常量按顺序使用iota 初始化时才有效。如果您需要适用于所有情况的东西,请使用显式切片。

【讨论】:

  • 我在我的脑海中来回思考这真的很酷,和认为它真的很脏。
  • 它只适用于iota。在常量可以是任何东西的一般情况下没有帮助。
  • 这段代码对我来说很糟糕。我更喜欢@captncraig 的答案,因为它始终使用定义的常量,而不是单独重新创建它们。函数调用还意味着每次调用时都会重建此切片,而不是在初始化时重建一次。
  • @Adrian 此处的优化可能是缓存 AllT 的结果,可能来自 init 函数。但是,是的,不是很有趣。添加更多代码,而不仅仅是硬编码一些查找。
  • 我同意 - 这仅适用于 iota,但它在我的情况下确实很有效 - 所以我会接受这个作为我的正确答案。特别喜欢init() 优化技巧。
【解决方案2】:

在运行时无法做到这一点,因为反射包不能用于它。你可以定义一个列表:

const(
    Created State = iota
    Modified
    Deleted
)
var allStates = []State{Created, Modified, Deleted}

你可以更进一步,添加一个字符串表示,或任何数量的其他东西。

您也许可以从源头生成这样一个列表,以使维护更容易,但我通常认为这样节省的时间并不值得。像stringer 这样的工具已经可以做到这一点。

【讨论】:

  • 它实际上可以在 runtime 使用 go/ast 和 co。虽然在这种情况下可能不明智。
  • @mkopriva,我不确定 go/ast 在您不再拥有源代码的情况下有何帮助。
  • 你是对的,我的错,大多数时候我在构建程序的机器上运行 Go,所以我总是忘记可执行文件可能在另一台机器上运行的事实,或者源可能不可用。
【解决方案3】:
package main

import (
    "fmt"
)

type State int

const (
    Created State = iota
    Modified
    Deleted
)

func (s State) Name() (name string) {
    switch s {
    case Created:
        name = "created"
    case Modified:
        name = "modified"
    case Deleted:
        name = "deleted"
    }

    return
}

func main() {
    states := States()
    fmt.Println(states)
}

func States() (states []State) {
    state := State(0)

    for {
        name := state.Name()
        if name == "" {
            break
        }

        states = append(states, state)
        state++
    }
    return
}

【讨论】:

  • 如果你要单独转储一个代码,你应该给出这个代码结果的例子:提供一个例子输入、运行和它的输出。
猜你喜欢
  • 2012-05-02
  • 2015-03-05
  • 2010-09-08
  • 1970-01-01
  • 2015-04-21
  • 2010-10-25
  • 1970-01-01
相关资源
最近更新 更多