Go 获取结构字段的简单字符串表示形式’;s型

Go 获取结构字段的简单字符串表示形式’;s型,go,abstract-syntax-tree,Go,Abstract Syntax Tree,使用Go,我在结构的字段列表上循环,如下所示: 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 } …并希望获得源代码中显示的fl

使用Go,我在结构的字段列表上循环,如下所示:

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
映射[byte]float64

ast package Type属性是一个
Expr
,因此我发现自己在使用类型开关和专门处理每种类型时陷入了困境——而我的唯一目标是将每个字段名右侧的纯字符串去掉,这似乎应该更简单


有一种简单的方法吗?

这里有两种方法,一种是表达式的类型,最终将在编译期间解析,另一种是确定该类型的代码

翻阅这些文件,我认为第一个根本不可用。但是,您可以通过在上使用
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

如果你想搞乱它,我会在中一起讨论这个问题。

我找到了一种方法,可以不使用原始源代码作为简单成员(而不是切片、数组或结构)的参考:

对于非简单成员,您只需要另一个case语句(即:
case*ast.ArrayType:
)。

这正是
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())
    }
}
输出:

field 0 has type "string"
field 1 has type "[]int"
field 2 has type "map[byte]float64"

在操场上试试:

你可以使用
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)
    ...
}

您是否尝试过文件字符串[fld.Type.Pos():fld.Type.End()]?既有帮助,也有不幸。:)文件业务在我的项目中处于上游,必须进行重组。
import (
    ...
    "go/types"
    ...
)

...

// typ is a *ast.StructType representing the above   
for _, fld := range typ.Fields.List {
    ...
    typeExpr := fld.Type
    typeString := types.ExprString(typeExpr)
    ...
}