go ast包默认不保留注释,需显式传入parser.parsecomments;注释统一存于ast.file.comments字段,类型为[]*ast.commentgroup;需手动通过token位置匹配注释与代码节点,并清洗前缀和空白。

Go ast 包默认不保留注释,必须显式启用
Go 的 ast.ParseFile 默认会丢弃所有注释节点,哪怕你看到源码里有 // 或 /* */,解析后的 *ast.File 里也找不到。这是因为注释在 Go 的语法分析阶段被当作“非结构化信息”跳过了。
要提取注释,必须传入 parser.ParseComments 模式:
file, err := parser.ParseFile(fset, filename, src, parser.ParseComments)
漏掉这个 flag 是最常见、也是唯一导致“怎么都拿不到注释”的原因。
注释存在 ast.File.Comments 字段,不是 AST 节点子树
注释不会挂在函数、变量等节点的 Doc 或 Comment 字段下(除非是 doc comment 且位置严格匹配),而是统一收在 *ast.File 的 Comments 字段中,类型为 []*ast.CommentGroup。
每个 *ast.CommentGroup 包含连续的注释行(比如一个 // 和紧跟着的另一个 // 会被合并),其 List 字段是 []*ast.Comment,而每个 *ast.Comment 的 Text() 方法返回带前缀的原始字符串(如 "// hello" 或 "/* world */"):
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
for _, group := range file.Comments {
for _, comment := range group.List {
fmt.Println(comment.Text()) // 输出 "// xxx" 或 "/* yyy */"
}
}
注意:comment.Text() 返回的是完整行内容,包括 //、/*、换行符等,需自行 trim 或正则提取纯文本。
想关联注释和具体代码节点?得靠位置匹配
Go ast 不提供“这个注释属于哪个函数”的直接引用关系。要实现类似 godoc 的文档绑定,必须手动比对位置(token.Position):
-
group.Pos()和group.End()给出注释整体的 token 位置范围 - 目标节点(如
*ast.FuncDecl)的Doc字段只在注释**紧贴其上方且无空行**时才被赋值;Comment字段则用于紧跟在节点后的行尾注释(如var x int // here) - 通用做法:遍历
file.Comments,对每个group检查它是否位于某个节点的Pos()正上方(即group.End() ,且中间无其他非空白/非注释 token),再结合行号距离做近似判断
这步没有银弹——标准库 go/doc 就是这么干的,但逻辑较重,简单工具建议只处理 node.Doc(即标准 doc comment)。
提取纯文本注释内容,别忘了去前缀和换行
直接调 comment.Text() 得到的是原始字符串,比如 "// Hello\n" 或 "/*\n * World\n */"。实际使用中通常需要清洗:
- 单行注释:用
strings.TrimPrefix(strings.TrimSpace(raw), "//") - 多行注释:用
strings.TrimPrefix(strings.TrimSuffix(raw, "*/"), "/*"),再按行 split + trim 每行的"* "前缀 - 更稳妥的做法是用
strings.Trim去掉首尾空白,再用正则^//\s*|^/\*\s*|\s*\*/$清理边界
别小看这个步骤——很多工具因为没处理 "//\t" 或 "/*\n * " 导致提取出空字符串或乱码空格。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










