我一直在使用go/ast解析go源代码,并将其复制到另一个文件中,作为供应商提供练习的一部分。我已经处理了大部分事情--函数、类型等等--但是我还在为使用iota的const声明而苦苦挣扎。我迭代了ast.File.Scope.Objects中的项目,并使用Scope.Outer == nil和它们的Decl == ast.ValueSpec复制了对象的源代码,基本上隐含了顶级变量和常量。
在一个类型的块中:
const (
a = iota
b
c
d
)...each其中一个注册为单独的对象,这是足够公平的。但是,我很难给它们赋值,因为当我遍历对象时,它们的顺序也可能会混乱。我可以看到这些的值为ast.Object.Data,但当它设置为1 <<象素时,它似乎也是关闭的,依此类推。有没有人有任何想法,我可以得到一个分组常量声明与正确的IOT值分配?
谢谢!
发布于 2021-11-05 16:59:30
我正在为exhaustive分析器解决这个问题,它在枚举发现阶段需要找到常量值。
游乐场: https://play.golang.org/p/nZLmgE4rJZH
考虑下面的ConstDecl。它由3个ConstSpec组成,每个ConstSpec有2个名称。(本例使用iota,但下面的方法一般适用于任何ConstDecl。)
package example
const (
A, B = iota, iota * 100 // 0, 0
_, D // 1, 100
E, F // 2, 200
)使用go/ast和go/types (或x/tools/go/packages),我们可以获得表示上述ConstDecl的*ast.GenDecl和包的*types.Info。
var decl *ast.GenDecl
var info *types.Info以下情况将适用于decl。
decl.Tok == token.CONST要获得常量值,我们可以这样做:
func printValuesConst(decl *ast.GenDecl, info *types.Info) {
for _, s := range decl.Specs {
v := s.(*ast.ValueSpec) // safe because decl.Tok == token.CONST
for _, name := range v.Names {
c := info.ObjectOf(name).(*types.Const)
fmt.Println(name, c.Val().ExactString())
}
}
}不出所料,这将打印出来:
A 0
B 0
_ 1
D 100
E 2
F 200旁注:用var代替const
注意,上面的代码适用于const块;对于var块,我们必须使用v.Values[i]来获取值(假设在索引i处存在一个值)。
游乐场:https://play.golang.org/p/f4mYjXvsvHB
decl.Tok == token.VARfunc printValuesVar(decl *ast.GenDecl, info *types.Info) {
for _, s := range decl.Specs {
v := s.(*ast.ValueSpec) // safe because decl.Tok == token.VAR
for i, name := range v.Names {
if len(v.Values) <= i {
fmt.Println(name, "(no AST value)")
continue
}
tv := info.Types[v.Values[i]]
if tv.Value == nil {
fmt.Println(name, "(not constant value)")
continue
}
fmt.Println(name, tv.Value.ExactString())
}
}
}https://stackoverflow.com/questions/66265149
复制相似问题