当前位置:   article > 正文

golang 使用AST语法树解析结构体_golang ast

golang ast

AST 语法树说明

在Go语言中,AST(Abstract Syntax Tree)即抽象语法树。它是一种用于表示源代码结构的数据结构,通过对源代码的语法分析,可以生成一棵AST,用于表示源代码的语法结构。

在Go语言中,AST是通过Go语言的内置包go/ast来实现的。该包提供了一系列类型和函数,可以用于生成和操作AST。

例如,下面是一段Go语言源代码:

package main

import "fmt"

func main() {
    fmt.Println("Hello, world!")
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

我们可以通过go/ast包中的函数来生成这段代码的AST。
例如,可以使用parser.ParseFile函数来解析一个源文件,并返回该文件的AST:

package main

import (
    "fmt"
    "go/ast"
    "go/parser"
    "go/token"
)

func main() {
    // 解析源文件
    fset := token.NewFileSet()
    f, err := parser.ParseFile(fset, "example.go", nil, 0)
    if err != nil {
        panic(err)
    }

    // 遍历AST
    ast.Inspect(f, func(n ast.Node) bool {
        // 处理节点
        fmt.Println(n)
        return true
    })
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

局部输出

&{<nil> 1 main [0xc0000a20c0 0xc000092420] scope 0xc000010400 {
        func main
}
 [0xc000092210 0xc000092240 0xc000092270 0xc0000922a0] [token parser nil nil panic ast ast bool fmt true] []}
main
<nil>
&{<nil> 15 import 22 [0xc000092210 0xc000092240 0xc000092270 0xc0000922a0] 78}
&{<nil> <nil> 0xc0000aa020 <nil> 0}
&{28 STRING "fmt"}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

上面的代码中,我们使用了parser.ParseFile函数来解析一个源文件,并返回该文件的AST。然后,我们使用ast.Inspect函数来遍历AST,并处理每个AST节点。在这个例子中,我们打印了每个节点的信息。

通过生成AST,我们可以对源代码的语法结构进行分析和操作。例如,可以通过遍历AST来寻找特定的节点,从而实现代码的查找、替换和重构等功能。

示例

解析结构体

  1. 创建名为src.go的文件,内容如下。稍后就来解析内容中的结构体
// package ast
package ast /* the name is ast */
import "fmt"

// StcA结构体说明
// descrpiton StcA
type StcA struct {
	FA string `json:"fa" form:"fa"` //测试字段A
	Fb string `json:"fb" form:"fb"`
}

type StcB struct {
	A, B, C int // associated with a, b, c
	// associated with x, y
	x, y float64    // float values
	z    complex128 // complex value
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  1. 创建测试文件main.go
package main

import (
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"io/ioutil"
	"strings"
	"testing"
)

func main() {
	src, _ := ioutil.ReadFile("src.go")
	f := token.NewFileSet()
	p, err := parser.ParseFile(f, "src.go", src, parser.ParseComments)
	if err != nil {
		t.Fatal(err)
	}

	for _, v := range p.Decls {
		var (
			structComment string
			structName    string
			fieldNumber   int
		)
		if stc, ok := v.(*ast.GenDecl); ok && stc.Tok == token.TYPE {
			//fmt.Println(stc.Tok) //import、type、struct...
			if stc.Doc != nil {
				structComment = strings.TrimRight(stc.Doc.Text(), "\n")
			}
			for _, spec := range stc.Specs {
				if tp, ok := spec.(*ast.TypeSpec); ok {
					structName = tp.Name.Name
					fmt.Println("结构体名称:", structName)
					fmt.Println("结构体注释:", structComment)
					if stp, ok := tp.Type.(*ast.StructType); ok {
						if !stp.Struct.IsValid() {
							continue
						}
						fieldNumber = stp.Fields.NumFields()
						fmt.Println("字段数:", fieldNumber)
						for _, field := range stp.Fields.List {
							var (
								fieldName    string
								fieldType    string
								fieldTag     string
								fieldTagKind string
								fieldComment string
							)
							//获取字段名
							if len(field.Names) == 1 {
								fieldName = field.Names[0].Name //等同于field.Names[0].String()) //获取名称方法2
							} else if len(field.Names) > 1 {
								for _, name := range field.Names {
									fieldName = fieldName + name.String() + ","
								}
							}
							if field.Tag != nil {
								fieldTag = field.Tag.Value
								fieldTagKind = field.Tag.Kind.String()
							}
							if field.Comment != nil {
								fieldComment = strings.TrimRight(field.Comment.Text(), "\n")
							}
							if ft, ok := field.Type.(*ast.Ident); ok {
								fieldType = ft.Name
							}
							fmt.Println("\t字段名:", fieldName)
							fmt.Println("\t字段类型:", fieldType)
							fmt.Println("\t标签:", fieldTag, "标签类型", fieldTagKind)
							fmt.Println("\t字段注释:", fieldComment)
							fmt.Println("\t----------")
						}
					}
				}
			}
		}
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81

输出:

结构体名称: StcA
结构体注释: StcA结构体说明
descrpiton StcA
字段数: 2
	字段名: FA
	字段类型: string
	标签: `json:"fa" form:"fa"` 标签类型 STRING
	字段注释: 测试字段A
	----------
	字段名: Fb
	字段类型: string
	标签: `json:"fb" form:"fb"` 标签类型 STRING
	字段注释: 
	----------
结构体名称: StcB
结构体注释: 
字段数: 6
	字段名: A,B,C,
	字段类型: int
	标签:  标签类型 
	字段注释: associated with a, b, c
	----------
	字段名: x,y,
	字段类型: float64
	标签:  标签类型 
	字段注释: float values
	----------
	字段名: z
	字段类型: complex128
	标签:  标签类型 
	字段注释: complex value
	----------
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/597742
推荐阅读
相关标签
  

闽ICP备14008679号