2026 年 11 月 5 日,我维护的开源项目 go-tour-i18n 收到了第一个 GitHub Issue。
看到有人主动反馈问题,我还是挺高兴的。毕竟这个项目投入了不少时间,能够有人实际阅读、使用,并且愿意指出问题,本身就是一件值得高兴的事情。
不过,这次 Issue 最终并没有产生任何代码修改。
我检查了问题对应的课程内容,又确认了 Go 官方上游的实现,最后选择将 Issue 关闭,原因是 not planned。
这并不是因为报告者说错了。恰恰相反,从 Go 语言语法的角度来看,报告者指出的问题完全正确。
只是这段看起来错误的代码,本来就是课程教学内容的一部分。
一、第一个 Issue:math.pi 应该改成 math.Pi
这次收到的是项目的 Issue #1:Fix typo in example: math.pi should be math.Pi。
报告者指出,某个示例使用了 math.pi,但 Go 语言区分大小写,因此正确写法应该是 math.Pi。
他还提供了错误写法和正确写法的对比。
错误代码:
fmt.Println(math.pi)正确代码:
fmt.Println(math.Pi)
单纯从代码正确性来看,这个反馈没有问题。
Go 语言中的标识符是区分大小写的。math.pi 和 math.Pi 并不是同一个标识符。
标准库 math 包提供的圆周率常量名称是 Pi,所以在正常代码中确实应该使用 math.Pi。
如果这是普通项目的业务代码,或者文档里无意写错的示例,那么修改它就是合理的。
但是,这次报告涉及的并不是普通代码,而是 Go Tour 中的一节教学课程。
这就需要进一步确认:示例代码到底是真的写错了,还是故意保留错误来帮助学习者理解某个知识点?
二、检查课程内容后,发现错误是故意设计的
我没有直接按照 Issue 的建议修改代码,而是先检查了对应的课程。
这段代码出现在 Go Tour 的 Exported names(导出名称) 课程中。
这节课主要介绍 Go 语言的一条重要规则:
在 Go 中,标识符首字符是 Unicode 大写字母,且处于允许导出的作用域时,该名称才是导出的,能够被其他包访问。
例如,math 包中的 Pi 是导出的常量,因此可以使用 math.Pi 访问。
而课程中的示例却故意写成:
package main
import (
"fmt"
"math"
)
func main() {
fmt.Println(math.pi)
}如果直接运行,就会发生编译错误。
乍看起来,这确实有些奇怪:为什么官方教程要提供一段不能正常编译的代码?
继续阅读课程说明后,原因就很清楚了。
课程要求学习者先运行代码,观察错误,然后将 math.pi 修改为 math.Pi,再重新运行。
也就是说,整个学习过程本来就分成几个步骤:
- 运行包含
math.pi的示例。 - 观察编译器给出的错误。
- 根据导出名称的规则,将
pi改成Pi。 - 再次运行,确认代码能够正常工作。
课程通过这个过程,让学习者实际体验 Go 语言的导出规则,而不只是阅读文字说明。
如果我直接将 math.pi 修改为 math.Pi,虽然代码可以正常编译,但学习者也就失去了观察错误并亲自修正的机会。
代码本身变得正确了,教学设计反而被破坏了。
三、进一步确认:Go 官方上游也保留了这个错误
确认教学意图之后,我又检查了项目对应的上游来源。
go-tour-i18n 的目标是为 Go 学习内容提供多语言支持,而不是随意修改官方课程的技术设计。
对于这类项目来说,判断某段代码是否应该修改,不能只看它能否独立运行,还需要考虑它在原始课程中的作用。
这次检查发现:
- 当前示例与官方
golang/website上游对应文件保持字节级一致。 - 官方上游仍然使用
math.pi。 - 课程正文明确要求学习者发现错误,再将其修改为
math.Pi。
这三个事实结合起来,已经足以确认:这不是因为翻译、复制或者维护失误而产生的错误。
它就是原始课程有意保留的教学示例。
因此,没有必要在我的项目里单独修改。
实际上,如果为了消除表面上的编译错误而修改它,还可能使本地内容偏离官方课程。
这对于一个以官方内容为基础的多语言项目来说,并不是理想的处理方式。
四、向报告者解释原因,然后关闭 Issue
确认问题后,我在 Issue 中给出了英文回复。
回复的主要内容是:
首先感谢报告者指出问题。
随后说明,math.pi 并不是拼写错误,而是 Go Tour 的 Exported names 课程有意设计的示例。
课程希望学习者先运行代码,观察编译错误,再主动将 math.pi 修改为 math.Pi。
这样能够帮助学习者理解 Go 语言中导出名称必须以大写字母开头的规则。
我也补充说明,这份文件与官方上游保持一致,而官方版本仍然使用相同的教学设计。
因此,目前不需要修改代码。

解释完成后,我准备关闭这个 Issue。
GitHub 提供了几种不同的关闭原因:
Close as completed:问题已经完成、修复或者解决。Close as not planned:不计划进行相应修改。Close as duplicate:该问题与其他 Issue 重复。
这次显然不适合使用 Close as completed。
因为我并没有进行代码修改,也没有完成某项修复工作。
同样,也不存在需要引用的重复 Issue。
因此,我最终选择了:
Close as not planned
2026 年 11 月 6 日,Issue #1 正式关闭。
整个处理过程没有产生代码变更,但问题已经得到了明确解释。
五、这次经历让我重新思考什么才算 Bug
如果只看 Issue 的标题,很容易认为这就是一个简单的拼写问题。
甚至不需要深入研究,就能知道 math.pi 在 Go 代码中无法正确引用标准库的圆周率常量。
如果我收到报告后立即修改代码,可能只需要几分钟。
但是,这样做反而会引入一个新的问题:原本用于教学的错误示例被我修正了。
这让我觉得,维护开源项目时,至少需要区分两种情况。
一种是真正的实现错误。
比如程序的实际行为与预期不一致,或者文档中的代码无意间出现了错误。这类问题通常应该修复。
另一种则是有意设计的特殊行为。
尤其是在教程、练习、测试用例等场景中,一段代码不能正常执行,并不必然意味着它存在需要修复的 Bug。
有时候,错误本身就是学习过程的一部分。
这两种情况,单靠代码能不能运行,并不能准确区分。
还需要理解代码所在的上下文,以及原始设计希望达到的目的。
对于 go-tour-i18n 来说,还有一个额外因素:上游内容是项目的重要依据。
如果发现看似异常的地方,先确认官方来源和原始意图,比直接进行本地修改更加稳妥。
六、关闭 Issue 不等于忽视反馈
这次经历还有一点让我印象比较深刻。
过去,我可能更容易把收到 Issue 理解为:项目出现了问题,需要尽快修复。
但这次实际处理后,我发现两者并不能简单画等号。
Issue 提供的是一个需要调查的问题,而不一定是一个已经确认的 Bug。
维护者需要判断问题是否成立、是否需要修改,以及什么样的处理方式才真正符合项目目标。
即使最终决定不修改代码,也应该尽量向报告者解释清楚原因。
这次报告者指出的语法问题确实存在,只不过它在课程中具有明确的教学用途。
因此,最终选择不修改代码,并不意味着反馈没有价值。
相反,如果没有这次反馈,我可能也不会特意重新核实这一段课程设计。
对于维护多语言技术文档的项目来说,这样的核实本身也是一次有价值的质量检查。
七、写在最后
这是 go-tour-i18n 收到的第一个 GitHub Issue。
最终结果很简单:
没有修改代码,没有产生修复提交,只是确认了官方课程的设计意图,向报告者解释原因,然后关闭 Issue。
但我觉得这次经历仍然值得记录。
它提醒我,维护开源项目并不是收到问题就立即修改,而是先确认问题,再决定是否需要修改。
尤其对于技术教程和文档项目,正确性不只是代码能否运行,也包括课程内容是否实现了原本的教学目的。
有些看起来不正确的代码,恰恰是为了教会读者什么才是正确的代码。
这次保留 math.pi,就是这样一个例子。
相关链接
- GitHub Issue:Fix typo in example: math.pi should be math.Pi #1
- 项目仓库:shuijingwan/go-tour-i18n
- Go Tour 官方课程:Exported names
Go 学习与文档多语言本地化项目
本系列完整记录 Go 学习与文档多语言本地化项目从 A Tour of Go 起步,逐步扩展到站点首页、项目说明页、学习内容、文档以及未来内容包的实际开发过程,包括架构设计、统一术语治理、整页翻译、结构保护、自动校验、独立质量审核、生产发布与长期维护。
项目源码:
✅ GitHub:shuijingwan/go-tour-i18n
语言版本:
当前跨项目目标语言池共包含 66 个语言版本。Go 项目本身目前提供 65 个社区 Production 语言版本,下面每一门 Go 语言版本都直接链接到其当前公开站点。语言列表沿用项目首页现有的展示顺序。
英语(美国)仅作为跨项目目标语言纳入列表,并不是单独的 Go Production 语言版本。当前 Go 的英文源内容仍为官方 generic English,因此英语(美国)链接到 Go 官方站点,而不是不存在的本地社区部署。
- 阿姆哈拉语
- 阿拉伯语
- 孟加拉语
- 葡萄牙语(巴西)
- 保加利亚语
- 加泰罗尼亚语
- 克罗地亚语
- 捷克语
- 丹麦语
- 荷兰语
- 英语(美国)(Go 官方英文站点)
- 英语(澳大利亚)
- 英语(加拿大)
- 英语(印度)
- 英语(新加坡)
- 英语(南非)
- 英语(英国)
- 爱沙尼亚语
- 菲律宾语
- 芬兰语
- 法语(法国)
- 法语(加拿大)
- 德语(德国)
- 德语(奥地利)
- 德语(瑞士)
- 希腊语
- 古吉拉特语
- 希伯来语
- 印地语
- 匈牙利语
- 印度尼西亚语
- 意大利语
- 日语
- 卡纳达语
- 哈萨克语
- 韩语
- 西班牙语(拉丁美洲)
- 拉脱维亚语
- 立陶宛语
- 马来语
- 马拉雅拉姆语
- 马拉地语
- 书面挪威语(Bokmål)
- 波斯语
- 波兰语
- 葡萄牙语(葡萄牙)
- 旁遮普语(果鲁穆奇文,印度)
- 罗马尼亚语
- 俄语
- 塞尔维亚语(西里尔文)
- 简体中文(中国大陆)
- 简体中文(新加坡)
- 斯洛伐克语
- 斯洛文尼亚语
- 西班牙语(西班牙)
- 斯瓦希里语(坦桑尼亚)
- 瑞典语
- 泰米尔语
- 泰卢固语
- 泰语
- 繁体中文(台湾)
- 繁体中文(香港)
- 土耳其语
- 乌克兰语
- 乌尔都语
- 越南语
项目正在持续扩展新的 Go 学习与文档内容,并长期维护各语言版本的术语一致性、翻译质量、独立审核、生产发布与后续更新。
本项目属于非官方社区多语言本地化项目,与 Go 官方无隶属、授权或背书关系。
