大家好,我是煎鱼。
前段时间二丫大佬反馈了一个较为细节的问题,当时在忙一下子没查阅出来。最近交流后有了新的验证和官方结论,获得一个新的小知识点,分享给大家。
该问题与 Go 模块的存储目录和方式有关。首先我们查看在本地 mod 目录下的相关目录。
如下图的模块存储路径:

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

这是怎么回事,目录名乱码了吗,还是说是一种加解密的编码?
在 golang.org/x/mod
的官方文档下 Escaped Paths[1] 我们能够找到相关的解释。如下图:

这个问题的缘由是因为 Go 模块是从 OS 文件系统读取数据的,模块不能单纯的依靠 OS 文件系统来区分大小写,也不能依靠网络服务器去区分。
也就是说,我们无法单纯依靠文件系统将 rsc.io/QUOTE
和 rsc.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
关注和加煎鱼微信,
一手消息和知识,拉你进技术交流群👇
你好,我是煎鱼,出版过 Go 畅销书《Go 语言编程之旅》,再到获得 GOP(Go 领域最有观点专家)荣誉,点击蓝字查看我的出书之路。
日常分享高质量文章,输出 Go 面试、工作经验、架构设计,加微信拉读者交流群,和大家交流!
原创不易 点赞支持