获取struct字段类型的简单字符串表示形式

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游乐场,如果你想搞砸它.


차유경*_*차유경 9

您可以使用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


mpo*_*ien 5

这正是包中的Fprintgo/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