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!")
}

我们可以通过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
    })
}

局部输出

&{<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"}

上面的代码中,我们使用了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. 创建测试文件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----------")
						}
					}
				}
			}
		}
	}
}

输出:

结构体名称: 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
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值