安全调用 parser.parsefile 需创建非 nil token.fileset、传入合法 utf-8 源码字节、启用 parser.parsecomments 模式,并严格检查 err;否则 file 为 nil,后续 ast.inspect 必 panic。

直接用 ast.Inspect 配合类型断言就能做绝大多数代码格式分析,不需要手写递归、不依赖 go/types,但必须配齐 token.FileSet、设对 parser.Mode、检查 err,否则一跑就 panic 或结果为空。
怎么安全调用 parser.ParseFile 解析字符串源码
传字符串进 parser.ParseFile 不是把代码丢进去就完事。它不校验 UTF-8、不跳过语法错误、也不帮你建 token.FileSet。漏掉任一环节,file 就是 nil,后续所有 .Pos() 返回 0,ast.Inspect 遍历直接 panic。
-
fset必须非nil:用token.NewFileSet()创建,别传nil或复用旧的(位置信息会错乱) -
src参数要非空:比如os.ReadFile("handler.go")的返回值,不是文件路径字符串 -
mode至少带parser.ParseComments:否则注释节点全丢,FuncDecl.Doc为空 - 必须检查
err != nil:语法错误、BOM 头、换行符混用(CRLF/LF)都可能导致err非nil,file为nil
为什么 ast.Inspect 是遍历首选,而不是手写递归
手写递归遍历 *ast.File.Decls 看似简单,但实际会漏掉大量节点:比如 func() {} 这类 *ast.FuncLit 不在 Decls 里;switch 分支里的 fallthrough 在 *ast.CaseClause.Body 中,不在顶层语句列表;type T struct{ f int } 的字段定义藏在 *ast.StructType.Fields,不经过 GenDecl 就根本碰不到。
-
ast.Inspect自动覆盖全部节点类型,包括*ast.FuncLit、*ast.CompositeLit、*ast.TypeSpec等冷门但高频结构 - 回调函数签名是
func(ast.Node) bool,返回false可立即中断(如只找第一个main函数) - 它跳过所有
nil字段,避免手写时因f.Type.Params == nil而 panic - 别在回调里修改节点:
AST是只读结构,改了也没用,还可能干扰后续遍历逻辑
遍历 *ast.FuncDecl 时为什么找不到函数名或参数名
*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是整个文件注释列表,不是函数专属
用 inspector 做批量节点匹配比 ast.Inspect 更省事
inspector 比 ast.Walk 更实用,因其自动处理节点父子关系、跳过注释/空白、支持按类型批量匹配,还能在不破坏 AST 结构的前提下安全地“看一眼就走”。
- 你不能直接
new一个inspector.Inspector;它必须由inspector.New([]ast.Node)构造,且参数必须是*ast.File切片(不是单个*ast.File) - 常见错误是传入
[]ast.Node{f}却忘了取地址,或把parser.ParseFile返回的*ast.File直接当ast.Node传进去导致 panic -
insp.Nodes()接收一个类型断言切片,内部做的是reflect.TypeOf(node).Name() == typeName级别的匹配,不支持接口(如ast.Expr)或嵌套结构体字段筛选 - 想抓所有函数调用,就得明确写
[]ast.Node{(*ast.CallExpr)(nil)}
最常被忽略的是:AST 本身不提供类型信息,*ast.Ident 只有名字和位置,没有真实类型;go:generate 这类编译指示注释只存在于原始文本中,不会进入 AST 节点,得从 CommentMap 单独提取。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











