
go/doc 包默认不将方法包含在 `pkg.funcs` 中,而是将其归类到各类型(`pkg.types`)的 `methods` 字段下;需遍历类型列表并访问其 `methods` 字段才能完整获取所有导出/未导出方法的文档信息。
Go 标准库中的 go/doc 包是用于解析 Go 源码并提取结构化文档的核心工具,广泛应用于 godoc 服务、IDE 插件及自动化文档生成系统。但一个常见误区是:方法(methods)不会出现在 Package.Funcs 列表中——无论是否导出,也无论是否启用 doc.AllDecls 或 doc.AllMethods 模式。
这是因为 go/doc 在语义建模上严格区分「包级函数」与「类型关联方法」:
- pkg.Funcs 仅包含定义在包作用域的函数(即 func name(...) { ... });
- 所有方法(包括接收者为指针或值、嵌入类型的方法)均归属到对应类型对象中,通过 pkg.Types[i].Methods 访问。
✅ 正确提取方法文档的步骤
- 使用 doc.New() 构建 *doc.Package;
- 遍历 pkg.Types,对每个 *doc.Type 实例:
- 检查 t.Name 确认类型名称;
- 遍历 t.Methods 获取每个 *doc.Func;
- 注意:Func.Recv 字段非空即表示该函数为方法(例如 *doc.Func{Recv: "T", Name: "String"})。
? 示例代码
pkg := doc.New(mainPkg, "./", doc.AllDecls)
// 1. 输出包级函数(不含方法)
log.Println("=== Package-level Functions ===")
for _, f := range pkg.Funcs {
log.Printf("Func: %s (Recv: %q)", f.Name, f.Recv) // f.Recv 为空字符串
}
// 2. 输出所有类型及其方法
log.Println("=== Types and Their Methods ===")
for _, t := range pkg.Types {
log.Printf("Type: %s", t.Name)
for _, m := range t.Methods {
recv := ""
if m.Recv != nil {
recv = m.Recv.String() // 如 "*T" 或 "T"
}
log.Printf(" Method: %s (%s)", m.Name, recv)
if m.Doc != "" {
log.Printf(" Doc: %s", strings.TrimSpace(m.Doc))
}
}
}⚠️ 注意事项
- doc.AllMethods 并非独立开关,它仅影响内部解析策略(如是否展开嵌入类型的方法),不会改变方法的存储位置;方法始终只存在于 Type.Methods。
- 若 pkg.Types 为空,可能因源码中无 type 声明,或 doc.New() 的 filter 参数误过滤了类型(默认 nil 表示不过滤)。
- Func.Recv 是 *ast.Field 类型,需调用 .String() 或解析 Field.Type 获取接收者类型字符串;直接打印可能输出内存地址。
- 未导出方法(小写首字母)仅在启用 doc.AllDecls 时可见;若省略该标志,Methods 列表将仅含导出方法。
✅ 总结
要完整提取 Go 包中所有函数和方法的文档,必须双路径遍历:
? pkg.Funcs → 获取包级函数;
? pkg.Types → t.Methods → 获取全部类型方法。
这是 go/doc 的设计契约,而非 bug。理解这一结构,是构建健壮 Go 文档分析工具的关键基础。










