如何使用Go AST/parser/packages获取任意作用域的所有结构体
Go代码任意作用域结构体提取方案
完全可以通过Go标准库的ast、parser模块提取所有作用域下的结构体,不管是包顶层定义的,还是函数、代码块内部定义的,核心是递归遍历AST所有节点,不要跳过嵌套作用域。
核心逻辑
- 所有Go的结构体定义,不管写在哪个位置,在AST中都会以「通用声明节点
ast.GenDecl包裹类型定义节点ast.TypeSpec,且TypeSpec的Type字段为*ast.StructType」的形式存在。 - 多数人只能拿到包级结构体,是因为仅遍历了
ast.File的顶层Decls声明列表,函数、if/for、匿名函数等内部的声明都挂在嵌套的语句节点下,只有深度递归遍历全树才能拿到。 - 不需要额外依赖第三方工具,标准库自带的
ast.Inspect方法就可以完成全节点遍历,golang.org/x/tools/go/packages仅在需要处理跨包依赖解析时才需要用到。
可直接运行的实现代码
package main import ( "go/ast" "go/parser" "go/token" "os" "path/filepath" "strings" ) // StructInfo 收集到的结构体元信息 type StructInfo struct { Name string // 结构体名称 FilePath string // 所在文件路径 IsExported bool // 是否为导出类型 StructNode *ast.StructType // 结构体AST节点,可进一步读取字段、注释、tag等内容 } // getAllStructs 遍历目标路径下所有.go文件,收集全作用域的结构体定义 func getAllStructs(srcPath string) ([]StructInfo, error) { var result []StructInfo fset := token.NewFileSet() err := filepath.Walk(srcPath, func(path string, info os.FileInfo, walkErr error) error { if walkErr != nil { return walkErr } // 跳过目录、非go文件、测试文件,可按需调整过滤规则 if info.IsDir() || !strings.HasSuffix(path, ".go") || strings.HasSuffix(path, "_test.go") { return nil } // 解析go源文件为AST fileAst, parseErr := parser.ParseFile(fset, path, nil, parser.ParseComments) if parseErr != nil { return parseErr } // 深度优先遍历所有AST节点,无作用域过滤 ast.Inspect(fileAst, func(n ast.Node) bool { // 匹配类型定义节点 typeSpec, ok := n.(*ast.TypeSpec) if !ok { return true } // 匹配底层类型为结构体的定义 structNode, ok := typeSpec.Type.(*ast.StructType) if !ok { return true } result = append(result, StructInfo{ Name: typeSpec.Name.Name, FilePath: path, IsExported: typeSpec.Name.IsExported(), StructNode: structNode, }) return true }) return nil }) return result, err }
扩展说明
- 上述代码可以直接拿到举例的包级
SomeType、someType2,以及main函数内部定义的someType3,哪怕结构体定义在嵌套的if块、for块、匿名函数内部,都不会遗漏。 - 如果需要区分结构体所属作用域(包级/函数级/块级),可以在遍历过程中维护一个作用域栈:遇到
*ast.FuncDecl时压入当前函数名,遇到*ast.BlockStmt时标记块层级,匹配到结构体时同步记录当前栈内的作用域信息即可。 - 如果需要解析结构体字段引用的外部包类型、处理go modules下的多包加载逻辑,可以替换手动遍历文件的逻辑,用packages模块一次性加载整包AST,后续的节点遍历、结构体匹配逻辑完全通用。
内容的提问来源于stack exchange,提问作者9gagger
相关产品推荐
相关产品推荐

