go - 使用 go/ast 进行 iota 声明
问题描述
我一直在使用 go/ast 来解析 go 源代码并将其复制到另一个文件中,作为 vendoring 练习的一部分。我已经处理了大多数事情——函数、类型等——但我正在努力处理使用 iota 的 const 声明。我正在遍历 ast.File.Scope.Objects 中的项目并复制具有 Scope.Outer == nil 及其 Decl == ast.ValueSpec 的对象的源,基本上暗示顶级变量和常量。
在类型块中:
const (
a = iota
b
c
d
)
...它们中的每一个都注册为一个单独的对象,这很公平。但是,我正在努力为它们分配值,因为当我遍历它们时,这些对象也可能是无序的。我可以将这些值视为 ast.Object.Data ,但是当它设置为 1 << iota 等时它似乎也关闭了。有人对我如何获得分配了正确 iota 值的分组 const 声明有任何想法吗?
谢谢!
解决方案
我正在为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
and go/types
(or 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.VAR
func 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())
}
}
}
推荐阅读
- sql - SQL 如何从单个列中的所有值创建 JSON 数组
- c++ - 使用可变参数模板时,如何获取第 n 个参数类型?
- java - 如何创建一个方法来对数组中的列求和?
- jquery - 如何从jquery中的日期引导日期选择器中获取日期?
- javascript - Vue:如何将 jar 库文件添加到 Vue.js 项目
- javascript - 没有“访问控制允许来源” - Firebase 功能
- json - 解析通过 curl 下载的 json 列表中的双引号值之间的值
- vb.net - 比较两个对象列表的每一行的属性并创建新对象
- flutter - 升级颤振版本时发布失败
- jquery - 鼠标移出后保持子菜单打开