直接用ast.Inspect配合类型断言可覆盖绝大多数静态分析,但必须防nil、带fset、设对mode,否则易panic或结果为空;parser.ParseFile前须检查fset非nil、文件名合理、mode含ParseComments或AllErrors、src非nil且err已校验。

直接用 ast.Inspect 配合类型断言就能覆盖绝大多数静态分析需求,但必须防 nil、带 fset、设对 mode,否则一跑就 panic 或结果为空。
parser.ParseFile 前必须检查这四件事
几乎所有崩溃都源于调用前上下文没配齐:
-
fset必须是token.NewFileSet()创建的非nil值,否则所有node.Pos()返回 0,定位失效 - 第二个参数(文件名)传空字符串
""可以,但若走磁盘读取,建议传绝对路径;若走内存解析(src非nil),它只是占位符,不校验存在性 - 第四个参数
mode不能为nil:要注释就加parser.ParseComments,要容忍语法错误继续解析就加parser.AllErrors -
src决定读取方式:传nil表示从文件路径加载;传字符串(如os.ReadFile结果)则必须非nil,否则解析器直接跳过
遍历 *ast.FuncDecl 时为什么找不到 main 或参数名
*ast.FuncDecl 字段命名和语义脱节,直接取容易 panic:
- 函数名在
f.Name.Name,不是f.Name——后者是*ast.Ident节点,未判空就取会崩 -
f.Type.Params和f.Type.Results可能为nil(比如func hello() {}),不是空切片,必须先判空再访问.List - 参数是
*ast.Field,名字在field.Names([]*ast.Ident),匿名参数(如func(int))该切片为空,取[0]必 panic -
f.Doc是函数上方的注释,但仅当mode包含parser.ParseComments才非nil;f.Comments是整个文件注释列表,不是函数专属
ast.Inspect 回调里怎么安全提取信息
它比手写递归稳,但用法有硬约束:
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
立即学习“go语言免费学习笔记(深入)”;
- 回调签名是
func(node ast.Node) bool,返回false表示“别往下走了”,适合找第一个main就停 - 类型断言必须带
ok判断:if f, ok := node.(*ast.FuncDecl); ok { },否则遇到*ast.FuncLit(闭包)会静默跳过 - 别在回调里改
node字段——AST 是只读结构,改了无效,还可能干扰后续遍历 - 需要父节点或作用域信息?
ast.Inspect不提供,得自己维护栈;真要改 AST,得用golang.org/x/tools/go/ast/astu
什么时候该换用 inspector 而不是 ast.Inspect
当你要对同一组 AST 文件做多次不同目的的遍历(比如先找未使用变量,再统计函数复杂度,再提取注释),ast.Inspect 就成了性能瓶颈——每次都要重新 DFS 整棵树:
- 初始化:
inspector.New([]*ast.File{f1, f2}),不是单个文件 - 只查函数?传
[]ast.Node{(*ast.FuncDecl)(nil)}给Preorder,避免无谓节点访问 - 需要前后序逻辑(比如进函数时计数、出函数时汇总),用
Nodes方法,它比Preorder多一层控制粒度 -
inspector不兼容老版本 Go 工具链,Go 1.21+ 更稳;低于此版本建议 stick withast.Inspect
最常被忽略的是:ast.Inspect 不提供类型信息,*ast.Ident 里只有名字和位置,没有真实类型;跨包符号引用、字段类型推导、接口方法查找这些事,必须引入 go/types 配合才能做。没上 go/types 就想解析 example_package.BaseObject 的字段,注定只能拿到标识符字符串。

















