首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >对iota声明使用go/ast

对iota声明使用go/ast
EN

Stack Overflow用户
提问于 2021-02-19 01:34:42
回答 1查看 111关注 0票数 2

我一直在使用go/ast解析go源代码,并将其复制到另一个文件中,作为供应商提供练习的一部分。我已经处理了大部分事情--函数、类型等等--但是我还在为使用iota的const声明而苦苦挣扎。我迭代了ast.File.Scope.Objects中的项目,并使用Scope.Outer == nil和它们的Decl == ast.ValueSpec复制了对象的源代码,基本上隐含了顶级变量和常量。

在一个类型的块中:

代码语言:javascript
复制
const (
    a = iota
    b
    c
    d
)

...each其中一个注册为单独的对象,这是足够公平的。但是,我很难给它们赋值,因为当我遍历对象时,它们的顺序也可能会混乱。我可以看到这些的值为ast.Object.Data,但当它设置为1 <<象素时,它似乎也是关闭的,依此类推。有没有人有任何想法,我可以得到一个分组常量声明与正确的IOT值分配?

谢谢!

EN

回答 1

Stack Overflow用户

发布于 2021-11-05 16:59:30

我正在为exhaustive分析器解决这个问题,它在枚举发现阶段需要找到常量值。

游乐场: https://play.golang.org/p/nZLmgE4rJZH

考虑下面的ConstDecl。它由3个ConstSpec组成,每个ConstSpec有2个名称。(本例使用iota,但下面的方法一般适用于任何ConstDecl。)

代码语言:javascript
复制
package example

const (
    A, B = iota, iota * 100 // 0, 0
    _, D                    // 1, 100
    E, F                    // 2, 200
)

使用go/astgo/types (或x/tools/go/packages),我们可以获得表示上述ConstDecl的*ast.GenDecl和包的*types.Info。

代码语言:javascript
复制
var decl *ast.GenDecl
var info *types.Info

以下情况将适用于decl

代码语言:javascript
复制
decl.Tok == token.CONST

要获得常量值,我们可以这样做:

代码语言:javascript
复制
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())
        }
    }
}

不出所料,这将打印出来:

代码语言:javascript
复制
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

代码语言:javascript
复制
decl.Tok == token.VAR
代码语言:javascript
复制
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())
        }
    }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66265149

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档