如下图的模块存储路径:

认真一看,会发现一个神奇的现象。那就是有的文件夹名称是带 ! 感叹号的。但是包本身并没有这样命名。

如下图红框中的感叹号:

这是怎么回事,目录名乱码了吗,还是说是一种加解密的编码?

golang.org/x/mod 的官方文档下 Escaped Paths[1] 我们能够找到相关的解释。如下图:

这个问题的缘由是因为 Go 模块是从 OS 文件系统读取数据的,模块不能单纯的依靠 OS 文件系统来区分大小写,也不能依靠网络服务器去区分。

也就是说,我们无法单纯依靠文件系统将 rsc.io/QUOTErsc.io/quote 区分开来。(至少 Windows 和 macOS 是这样)

因此 Go 模块需要一种安全的转义方式,使大多数导入路径的结果保持不变,避免名称的冲突。

经过各方面的考量,Go 团队得出的安全转义的方式是:用感叹号替换每个大写字母,后面跟一个小写字母

例如:

github.com/Azure/azure-sdk-for-go ->  github.com/!azure/azure-sdk-for-go. github.com/GoogleCloudPlatform/cloudsql-proxy -> github.com/!google!cloud!platform/cloudsql-proxy github.com/Sirupsen/logrus -> github.com/!sirupsen/logrus.

注:Go 模块导入路径不允许使用 ! 感叹号 ,因此无需定义如何转义 ! 感叹号。

可能会有同学想说,全转大写或小写。这样其实也是不行的,因为会出现重名的情况,直接就覆盖了。

更甚者,例如:DataDog 这个模块,它随着时间的推移改变了大小写的命名,还改了几次。因此如果你 mod 目录下有多个版本,现在这种设计下,你会有一个 !d!a!t!a-!d!o!g 和一个 !data!dog 目录。

总结来讲,Go 模块(mod)的会将路径中的大写字母转换为相应的小写字母,并在前面加上感叹号,以避免在大小写不敏感的文件系统中发生大小写冲突。也就有了这看起来那么 “奇怪” 的目录名。

感觉神奇的 Go 知识又多掌握了一个!

推荐阅读

参考资料

[1]

Escaped Paths: https://pkg.go.dev/golang.org/x/mod/module#hdr-Escaped_Paths

个人笔记记录 2021 ~ 2025