使用Go的ast package,我循环遍历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
}
...并希望获得fld.Type的简单字符串表示,因为它出现在源代码中,例如“[] int”或“map [byte] float64”。
ast包field type Type属性是一个Expr,所以我发现自己使用类型开关进入杂草并专门处理每种类型 - 当我唯一的目标是将纯字符串输出到每个字段名称的右侧,看起来应该更简单。
有简单的方法吗?
答案 0 :(得分:14)
你可以在这里找到两件事,一个是表达式的类型,最终会在编译时被解析,另一个是代码确定那种类型。
通过文档挖掘,我不相信第一个是可用的。不过,您可以在Node
上使用End()
和Pos()
来获取。
快速示例程序:
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)
}
}
打印:
string
[]int
map[byte]float64
我在golang playground中一起讨论这个问题,如果你想搞砸它。
答案 1 :(得分:2)
我找到了一种方法来做到这一点,而不使用原始源代码作为简单成员(不是切片,数组或结构)的参考:
for _, field := range fields {
switch field.Type.(type) {
case *ast.Ident:
stype := field.Type.(*ast.Ident).Name // The type as a string
tag = ""
if field.Tag != nil {
tag = field.Tag.Value //the tag as a string
}
name := field.Names[0].Name //name as a string
...
对于非简单成员,您只需要另一个案例陈述(IE:case *ast.ArrayType:
)。
答案 2 :(得分:1)
我发现最好的方法是使用Fprint method in the go/printer package。
它接受任何AST节点作为参数,并将其字符串表示形式写到任何io.Writer
中。
您应该可以在示例中使用它,如下所示:
for i, fld := range typ.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 name %q", i, typeNameBuf.String())
}