Go types.Package.Scope 怎样列出包导出 API
如果你已经用 go/types 完成了一个包的类型检查,想把这个包对外提供的类型、常量、变量和函数列出来,最短路径是:先取 pkg.Scope(),再用 Names() 得到名称,用 Lookup() 取回对象,最后检查对象的 Exported() 和 Type()。
这里的关键是“包级”。Package.Scope() 保存的是包级声明,不是每个文件的局部作用域,也不是结构体的方法集。下面按一个小型 API 清单场景,把这套写法拆成可以直接放进分析工具的配方。
Package.Scope 到包级对象的最小配方
Package.Scope() 返回包级作用域,里面的对象类型主要包括 TypeName、Const、Var 和 Func。如果包对象还不完整,Scope 也可能是不完整的;因此自动生成 API 文档时,应把 pkg.Complete() 一并作为输入状态记录下来。

假设你已经从类型检查器拿到了 pkg *types.Package,最小入口就是这一行:
// pkg 是类型检查结果中的包对象,不是手工拼出的空 Package。
scope := pkg.Scope()
// Names 返回当前作用域中的名称,并且已经按名称排序。
names := scope.Names()
fmt.Println("package:", pkg.Path(), "complete:", pkg.Complete())
fmt.Println("names:", names)
Names() 的排序很有用:输出不会随着源文件声明顺序变化而变化,适合生成文档、做快照或比较两个包的 API 名单。但它只返回名字,不会直接告诉你每个名字是函数、类型还是常量。
用 Names 和 Lookup 拼出导出 API 清单
一个可复用的做法是遍历名称,再对每个名称调用 Lookup。Lookup 找不到对象时返回 nil,所以保留这个判断可以让代码对不完整或人工构造的 Scope 更稳妥。
// ExportedAPI 把包级导出对象转换成稳定的展示数据。
type ExportedAPI struct {
Name string
Kind string
Type string
}
func ListExportedAPI(pkg *types.Package) []ExportedAPI {
if pkg == nil {
// nil 包对象没有可列出的业务 API,避免继续解引用。
return nil
}
scope := pkg.Scope()
result := make([]ExportedAPI, 0, scope.Len())
for _, name := range scope.Names() {
// Names 已排序,因此 result 的顺序天然稳定。
obj := scope.Lookup(name)
if obj == nil || !obj.Exported() {
// 小写名称或缺失对象不属于对外 API。
continue
}
result = append(result, ExportedAPI{
Name: obj.Name(),
Kind: reflect.TypeOf(obj).String(),
Type: types.TypeString(obj.Type(), nil),
})
}
return result
}
这段代码需要导入 fmt、reflect 和 go/types。reflect.TypeOf(obj).String() 只是为了在示例中显示对象实现类型;如果你的输出协议不需要这个字段,可以把 Kind 去掉,保留 Name 与 Type。
为什么要同时使用 Exported、Name 和 Type
Names() 只负责列举作用域中的名字;它不会替你完成 Go 语言的导出判断。导出判断应该交给对象的 Exported() 方法,它依据标识符是否以大写字母开头判断,而不是依据你当前运行工具的包路径。

取到对象后,三个字段的用途可以这样分工:
| 信息 | 读取方式 | 适合用途 |
|---|---|---|
| 名称 | obj.Name() | 展示 API 名称、生成索引键 |
| 是否导出 | obj.Exported() | 过滤包的公开边界 |
| 声明类型 | obj.Type() | 生成签名摘要或类型说明 |
| 所属包 | obj.Pkg() | 区分本包对象与被插入的对象 |
不要把 obj.String() 当成稳定的机器协议。它更适合调试或人读的日志;如果要存储 API 索引,建议单独保存名称、对象类别和类型字符串,并自行定义版本化格式。
前端配方式变体:只查一个导出名称
如果页面只需要判断某个 API 是否存在,没有必要先遍历全部名称。直接调用 Lookup 即可;这样也能把“是否存在”和“是否导出”放在一个清晰的判断中。
func FindExported(pkg *types.Package, name string) (types.Object, bool) {
if pkg == nil {
// 空包对象没有可查询的作用域。
return nil, false
}
obj := pkg.Scope().Lookup(name)
if obj == nil || !obj.Exported() {
// 未声明、未导出都按“不可作为公开 API 使用”处理。
return nil, false
}
return obj, true
}
这个变体适合文档站的单项查询、补全提示或 API 兼容性比较。若要批量生成目录,仍然优先选择 Names(),因为它给出的排序由 go/types 负责,不需要在业务层重复排序。
几个容易踩到的边界
- Scope 不是所有可见成员。 它表示包级声明;结构体字段和方法需要通过类型信息、方法集或选择器相关 API 另行分析。
- Scope 不等于文件 Scope。 多个源文件的包级声明会汇总到同一个包 Scope 中,不能用文件遍历次数推断 API 数量。
- 不完整包要标记状态。 官方文档说明,包完整时 Scope 至少包含全部导出对象;不完整包不应该被当成完整 API 清单。
- 不要用声明顺序当稳定顺序。 使用
Names()的排序结果,再根据名称查对象。 - nil 接收者有特殊语义。 官方文档规定,
nil的Package.Scope()返回 Universe Scope;业务代码仍建议显式检查 nil,避免把预声明标识符误当成目标包 API。
一张速查表
| 目标 | 推荐写法 | 注意 |
|---|---|---|
| 拿包级作用域 | pkg.Scope() | 来源应是类型检查后的 Package |
| 列出全部名称 | scope.Names() | 结果已按名称排序 |
| 查单个对象 | scope.Lookup(name) | 不存在时返回 nil |
| 过滤公开 API | obj.Exported() | 不只看名字是否在列表中 |
| 读取类型 | obj.Type() | 按对象类型分别格式化更合适 |
| 判断清单是否完整 | pkg.Complete() | 不完整时应在结果中保留状态 |
所以,标题问题的最终配方可以压缩成:pkg.Scope().Names() 负责稳定枚举,scope.Lookup(name) 负责取回对象,obj.Exported() 负责公开性判断,obj.Type() 负责类型展示。把 pkg.Complete() 一并记录,生成的 API 清单才不会把“不完整”误报成“没有”。
相关问题
Scope.Names 会返回未导出的名称吗?
会。它返回当前作用域中的全部元素名称,导出过滤要在取回对象后使用 Exported() 完成。
怎样读取一个函数的参数和返回值?
先通过 Lookup 得到对象,再把 obj.Type() 断言或处理为 *types.Signature,然后读取参数和结果元组。
Package.Scope 能列出结构体方法吗?
不能直接列出。Package.Scope 保存包级声明;结构体方法属于类型的方法信息,应围绕具体命名类型和方法集单独查询。
为什么 API 清单有时比源文件里的导出声明少?
优先检查 pkg.Complete()、导入器返回的数据是否完整,以及你是否把文件级或构建条件下的声明混在了比较范围里。不要先假设是 Names() 丢了数据。
Go ast.CommentMap 怎样在删除声明后保留关联注释
- 上一篇
- Go ast.CommentMap 怎样在删除声明后保留关联注释
- 下一篇
- Go CommentMap 为什么会把注释关联到外层声明
-
- Golang · Go教程 | 31分钟前 | Go教程 · Go scope go/types Complete types.Package MarkComplete SetImports
- Go 自建 types.Package 怎样标记已经完成的包信息
- 115浏览 收藏
-
- Golang · Go教程 | 31分钟前 |
- Go types.Package.Imports 怎样生成包的直接依赖图
- 388浏览 收藏
-
- Golang · Go教程 | 39分钟前 | go · Go go/types comma-ok TypeAndValue HasOk
- Go TypeAndValue.HasOk 怎样识别可使用双返回值的表达式
- 348浏览 收藏
-
- Golang · Go教程 | 42分钟前 | Go 可寻址 TypeAndValue Addressable
- Go TypeAndValue.Addressable 怎样识别可取地址表达式
- 187浏览 收藏
-
- Golang · Go教程 | 45分钟前 |
- Go TypeAndValue 怎样提取常量表达式的精确值
- 314浏览 收藏
-
- Golang · Go教程 | 51分钟前 | go · 源码分析 · go/types InitOrder Go types.Initializer
- Go types.Initializer 怎样表示一次赋值产生多个变量
- 277浏览 收藏
-
- Golang · Go教程 | 58分钟前 | Go 初始化顺序 包级变量 Info.InitOrder
- Go Info.InitOrder 怎样列出包级变量初始化依赖顺序
- 112浏览 收藏
-
- Golang · Go教程 | 1小时前 | Go types.Sizes Alignof 字段对齐
- Go types.Sizes.Alignof 怎样解释字段对齐要求
- 241浏览 收藏
-
- Golang · Go教程 | 1小时前 |
- Go types.SizesFor 怎样按目标架构计算类型尺寸
- 443浏览 收藏
-
- Golang · Go教程 | 1小时前 | Go 类型检查 FileSet types.NewChecker
- Go 自建类型检查器怎样复用解析阶段的 FileSet
- 228浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 967次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 974次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 1083次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 1059次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 898次使用
-
- Java 性能优化上线清单:从定位、改造到灰度发布
- 2026-06-11 860浏览
-
- Spring Boot 压测验证:Gatling、JMeter 与性能回归门禁
- 2026-06-11 843浏览
-
- Java NMT 非堆内存排查:Direct Buffer、线程栈与 Metaspace 分析
- 2026-06-11 826浏览
-
- Spring Boot 容器内存优化:JVM 堆、非堆与 MaxRAMPercentage
- 2026-06-11 809浏览
-
- Tomcat 连接与线程参数调优:maxThreads、acceptCount 与 KeepAlive
- 2026-06-11 792浏览

