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())
}
}
}
}
}
map[string]interface{}
or maybe a[]interface{}
. – TransistorizeState
so this isn't a big deal, but it needs to be noted for the general case. – Transistorizego/ast
and its associated packages. It's quite the job though, so unless you have an unmaintainable number of cases where you need this I recommend doing it manually as suggested in @captncraig's answer. – SkipState
is specified in the constant declarations). There's also no reason to put them in a[]interface{}
- they could go in a[]State
and remain type-safe. – Knack