Mat*_*man 11 abstract-syntax-tree go
使用Go的ast包,我循环遍历struct的字段列表,如下所示:
type Thing struct {
Field1 string
Field2 []int
Field3 map[byte]float64
}
// typ is a *ast.StructType representing the above
for _, fld := range typ.Fields.List {
// get fld.Type as string
}
Run Code Online (Sandbox Code Playgroud)
...并希望获得fld.Type的简单字符串表示,因为它出现在源代码中,例如"[] int"或"map [byte] float64".
ast包字段类型 Type属性是一个Expr,所以我发现自己使用类型开关进入杂草并专门处理每种类型 - 当我唯一的目标是获取每个字段名称右侧的普通字符串时,这似乎应该更简单.
有一个简单的方法吗?
Kev*_*ose 14
这里有两件事你可以得到,一个是在编译期间最终会被解析的表达式的类型,另一个是确定该类型的代码.
通过文档挖掘,我不相信第一个是可用的.但是,你可以通过使用End()和Pos()开启Node.
快速示例程序:
package main
import (
"fmt"
"go/ast"
"go/parser"
"go/token"
)
func main() {
src := `
package foo
type Thing struct {
Field1 string
Field2 []int
Field3 map[byte]float64
}`
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, "", src, 0)
if err != nil {
panic(err)
}
// hard coding looking these up
typeDecl := f.Decls[0].(*ast.GenDecl)
structDecl := typeDecl.Specs[0].(*ast.TypeSpec).Type.(*ast.StructType)
fields := structDecl.Fields.List
for _, field := range fields {
typeExpr := field.Type
start := typeExpr.Pos() - 1
end := typeExpr.End() - 1
// grab it in source
typeInSource := src[start:end]
fmt.Println(typeInSource)
}
}
Run Code Online (Sandbox Code Playgroud)
这打印:
string
[]int
map[byte]float64
Run Code Online (Sandbox Code Playgroud)
我一起在golang游乐场,如果你想搞砸它.
您可以使用go/types ExprString
这适用于复杂的类型,如[]string、[]map[string]string等。
import (
...
"go/types"
...
)
...
// typ is a *ast.StructType representing the above
for _, fld := range typ.Fields.List {
...
typeExpr := fld.Type
typeString := types.ExprString(typeExpr)
...
}
Run Code Online (Sandbox Code Playgroud)
https://golang.org/src/go/types/exprstring.go
这正是包中的Fprint的go/printer用途。它将任何 AST 节点作为参数并将其字符串表示形式写入io.Writer.
您可以在示例中使用它,如下所示:
package main
import (
"bytes"
"fmt"
"go/ast"
"go/parser"
"go/printer"
"go/token"
"log"
)
func main() {
src := `
package foo
type Thing struct {
Field1 string
Field2 []int
Field3 map[byte]float64
}`
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, "", src, 0)
if err != nil {
panic(err)
}
typeDecl := f.Decls[0].(*ast.GenDecl)
structDecl := typeDecl.Specs[0].(*ast.TypeSpec).Type.(*ast.StructType)
for i, fld := range structDecl.Fields.List {
// get fld.Type as string
var typeNameBuf bytes.Buffer
err := printer.Fprint(&typeNameBuf, fset, fld.Type)
if err != nil {
log.Fatalf("failed printing %s", err)
}
fmt.Printf("field %d has type %q\n", i, typeNameBuf.String())
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
field 0 has type "string"
field 1 has type "[]int"
field 2 has type "map[byte]float64"
Run Code Online (Sandbox Code Playgroud)
在操场上试试:https : //play.golang.org/p/cyrCLt_JEzQ