Here is an example:
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.
}
The use case for this is to create a Finite State Machine (FSM). Being able to get all constants will help me in writing a test case that will ensure that every new value has a corresponding entry in the FSM map.
If your constants are all in an order, you can use this:
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
}
You can also cache the output in e.g. init()
. This will only work when all constants are initialised with iota
in order. If you need something that works for all cases, use an explicit slice.
There is no way to do this at runtime, as the reflect package cannot be used for it. You could define a list:
const(
Created State = iota
Modified
Deleted
)
var allStates = []State{Created, Modified, Deleted}
You may go further and add in a string representation, or any number of other things.
You may be able to generate such a list from the source to make maintenance easier, but I generally don't think that saves enough time to be worth it. There are tools like stringer that can already do some of that.
Since you talking about a test-case I assume you have the type available as well as the file where the constants are defined in. I used for a similar problem the following approach (go playground):
package main
import (
"fmt"
"go/ast"
"go/importer"
"go/parser"
"go/token"
"go/types"
"log"
"strconv"
"strings"
)
type InterestingType uint64
const const_go = `
package p
type InterestingType uint64
const (
A InterestingType = iota << 1
B
C
)
type UninterestingType int
const (
D UninterestingType = iota
E
)
`
func main() {
constantValues := []InterestingType{}
ConstantsOf("InterestingType", const_go, func(v string) {
value, err := strconv.ParseUint(v, 0, 64)
if err != nil {
log.Fatal(err)
}
constantValues = append(
constantValues, InterestingType(value))
})
fmt.Printf("%#v\n", constantValues)
}
func ConstantsOf(ctype string, file string, value func(string)) {
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, "const.go", file, 0)
if err != nil {
log.Fatal(err)
}
// Obtain type information.
conf := types.Config{Importer: importer.Default()}
info := &types.Info{
Defs: make(map[*ast.Ident]types.Object),
}
_, err = conf.Check("p", fset, []*ast.File{f}, info)
if err != nil {
log.Fatal(err)
}
for _, d := range f.Decls {
for _, s := range d.(*ast.GenDecl).Specs {
v, ok := s.(*ast.ValueSpec)
if !ok {
continue
}
for _, name := range v.Names {
c := info.ObjectOf(name).(*types.Const)
if strings.HasSuffix(c.Type().String(), ctype) {
value(c.Val().ExactString())
}
}
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With