Go go/doc.Examples 怎样区分空输出与未声明输出
来源:17golang原创
时间:2026-11-05 19:31:11 145浏览 收藏
go/doc.Examples 返回的 Example.Output 为空字符串,既可能表示没有输出声明,也可能表示显式声明了空输出。需要同时读取 EmptyOutput:它为 true 表示期望空输出;它为 false 且 Output 为空时,表示未声明输出。不要仅用 Output == "" 把两者合并。
官方地址:https://pkg.go.dev/go/doc
先确定工具只抽取声明
为文档系统整理示例时,可以把测试源码当作文本交给 parser,再让 doc.Examples 从 AST 中抽取记录。这个工具的职责是识别注释声明,不是运行示例。对来源代码保持这个边界,既能避免误把预期文本写成实测输出,也不需要执行源文件内的函数。
本文示例在普通 Go 程序中使用标准库,不启动子进程、不调用 go test,也不把 Play 非空视为执行成功。本次文章没有运行下面的代码。
保留注释后,再提取 Example
关键参数是 parser.ParseComments。输出声明存在于注释中,解析时丢掉注释,后续自然无法可靠地区分状态。下面把三个原创示例放在一个源码字符串里,分别表达空输出、无声明和非空输出。
package main
import (
"fmt"
"go/doc"
"go/parser"
"go/token"
)
// classify 只解释源文件里的输出声明,不判定示例是否运行成功。
func classify(e *doc.Example) string {
if e.EmptyOutput {
return "显式空输出"
}
if e.Output != "" {
return "声明非空输出"
}
return "未声明输出"
}
func main() {
// 三种原创输入;字符串里的代码仅作为解析材料,不会被调用。
src := `package sample_test
import "fmt"
// Example_blank 声明预期没有输出。
func Example_blank() {
// Output:
}
// Example_missing 没有输出声明。
func Example_missing() {
// 这里只是普通注释。
}
// Example_text 声明预期文本。
func Example_text() {
fmt.Println("ready")
// Output: ready
}
`
fset := token.NewFileSet()
file, err := parser.ParseFile(fset, "sample_test.go", src, parser.ParseComments)
if err != nil {
fmt.Println("解析失败:", err)
return // 解析失败时不生成看似完整的声明清单。
}
for _, e := range doc.Examples(file) {
fmt.Printf("%s: %s, Output=%q, EmptyOutput=%t\n",
e.Name, classify(e), e.Output, e.EmptyOutput)
}
}
Example_blank 的 Output 为空,EmptyOutput 为 true;Example_missing 的 Output 为空,EmptyOutput 为 false;Example_text 的 Output 包含 ready 对应的预期文本。这里给出的是代码语义推导,没有伪造终端运行记录。打印时使用 %q 是为了让换行等不可见字符可辨识。

按两个字段保存三种声明状态
| EmptyOutput | Output | 应保存的含义 |
|---|---|---|
| true | 空字符串 | 显式期望空输出 |
| false | 非空文本 | 声明了预期文本 |
| false | 空字符串 | 未声明输出 |
对标准库抽取出的记录,上面三种组合足以解决本题。若业务代码手动构造 Example 并同时设置相互矛盾的字段,应另行定义输入契约,不能把手工对象的组合归咎于解析器。示例的 Unordered 字段另外表示输出顺序语义,不应被用来代替 EmptyOutput。
不要为省事对 Output 做 TrimSpace 后再覆盖原字段:原始文本有助于追踪声明来源。业务需要展示摘要时,可以额外保存展示字段,让抽取值和呈现值各有用途。

处理权限和审计记录时保留边界
实际接入仓库扫描时,先限定输入目录和源码大小,读取失败或语法解析失败单独记录。解析不执行函数,但仍会消耗内存和 CPU;面对不可信大文件,不应省略资源限制。本文的内嵌字符串只是为了把核心处理保持为一个可读例子。
清单可保留仓库相对文件名、Example.Name、Order、Output、EmptyOutput 和解析状态。doc.Examples 按 Name 排序;若报告希望展示源码顺序,应使用 Order 作依据,不能把返回列表顺序直接当作源文件顺序。
发布文档前,措辞应是“声明预期为空”或“未声明输出”,而非“执行后没有输出”。是否编译通过、运行时是否有副作用、输出是否匹配,需要独立的执行证据,静态抽取本身不能回答。
只有普通注释,函数体也没有打印,算空输出吗?
不算显式空输出声明。没有 Output 注释时,不能仅根据函数看起来安静就设置 EmptyOutput。
Play 非空是不是已经运行过?
不是。它是可用于表示完整示例程序的 AST 字段,不是运行回执。
直接调用 Examples 可以拿到 Suffix 吗?
该入口不填充 Suffix;官方文档说明 NewFromFiles 会为其从测试文件找到的示例填充此字段。不要据此误判输出声明缺失。
-
860 收藏
-
843 收藏
-
826 收藏
-
809 收藏
-
792 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习