Go语言(golang)第一个正式版Go1发布了,但是这个新兴的编程语言还是非常不完善。这不,我(Liigo)又发现它的编译器竟然不支持编译带BOM的UTF-8编码的.go源文件。这就很奇怪,该语言明明要求源代码文件.go必须是UTF-8编码,但有不允许带UTF-8 BOM。要知道,这个世界上带BOM的文件太多了,很多文本编辑器/代码编辑器/IDE都会默认生成带有BOM的UTF-8文件。如果仅仅因为源代码文件多了BOM,编译器将不能编译这个文件,我觉得它太低能了。
Go语言编译器(gc)不支持带有BOM的UTF-8源文件:
Golang's compiler (gc) don't accept the .go files with UTF-8 BOM:
好在Go语言是开源项目,我(Liigo)来贡献代码,让它支持编译带UTF-8 BOM的.go源代码文件。经过分析后发现,Go语言编译器(gc)源代码中有两处地方涉及从磁盘文件中读取.go文件:一个是C语言写的词法分析器(src/cmd/gc/lex.c),一个是Go语言写的.go文件解析器(src/pkg/go/parser/interface.go)。解决思路也很简单,就是从磁盘读取文件内容后,判断前三个字节,与UTF-8 BOM的三个字节(0xef, 0xbb, 0xbf)核对,如果一致则忽略这三个字节,从第四个字节算作文件的真正内容,然后再交给词法分析器和解析器处理,后面就一切正常了。
Go语言的词法分析器是用C语言手工编写的,其中用到了lib9/libbio库,是一个磁盘文件读写缓冲区,逐字节读取该缓冲区时,它可以做到“反读取”最近的4个字节,就是说,假设我刚刚读取了abcd是个字节,现在我“反读取”后两个字节,实际上就相当于我刚刚读取了ab还没有读取cd。利用它的这个“凡读取”机制,恰恰可以很容易的忽略掉UTF-8文件最前面的BOM:首先读出前三个字节,如果这三个字节正好是UTF-8 BOM的三个字节(0xef, 0xbb, 0xbf),那么直接把刚刚读出的三个字节扔掉就完事了,后面词法分析器处理时正好从BOM后面的字节开始读取;如果已经读出的三个字节不是UTF-8
BOM呢,需要“反读取”,即把他们再放回去,就当作我没有读取过它们。修改后的代码如下:
Go语言的源代码解析器(pkg/go/parser)是用Go语言自己编写的,其功能是解析.go源代码文件为语法树。Go语言官方提供的go build命令用pkg/go/parser分析处理编译前的库依赖项。go build命令(pkg/go/parser)是把.go文件整个读入内存后再解析的。我要做的工作就是,在pkg/go/parser开始正式解析前,把前面可能存在的UTF-8 BOM删除掉即可,这个工作仅仅涉及Go语言中byte slice的基本操作,是很轻量级的廉价操作。
我把上面修改的代码提交到Go语言官方源码库,代码审查页面地址是:
http://codereview.appspot.com/6036054/, 或http://codereview.appsp0t.com/6036054/。
但是Go语言的作者/官方开发者拒绝这一改进。Go开发组老大Rob Pike亲自回复给出就拒绝的理由:
在我看来,理由非常勉强,在逻辑上甚至都不成立。哦,既然规定了.go必须使用UTF-8编码,所以就一定不能加UTF-8 BOM了?加了BOM就拒不接收了?前面已经说过了,很多文本编辑器都会自动添加UTF-8 BOM的,怎么到你这里就不合法了。一个很现实的例子是,Windows XP / Windows 7系统内置的“记事本”程序(notepad.exe)在保存UTF-8文件时是一定会自动添加UTF-8 BOM的。也就是说,你想用记事本保存的.go源代码是一定不能编译通过的。但就是这么严重的问题,Go作者们就是不当一回事;这么容易就可以改进的问题,他们就是拒绝改进。生生的为用户使用go语言又凭空制造一道阻力。要说是面临技术方案的妥协选择折中还可以理解,偏偏要在无关紧要的地方坚持己见宁死不去考虑方便用户。我只能说他们是死脑筋。类似的情况我遇到也不止一次了,总结下来就是:技术大牛挂帅做产品害人害己;闭门造车的代价是死都不知道咋死的。(这样的总结也为我们做易语言产品敲响了警钟:绝对不能单纯以技术人员的心态做产品。)
分享到:
相关推荐
php 字符编码转换类,支持ANSI、Unicode、Unicode big endian、UTF-8、UTF-8+Bom 互相转换。
vim-compiler-go - go(golang)的Vim编译器插件在保存时高亮显示语法错误
go-ole - golang的Win32 OLE实现
golang design pattern; 设计模式golang版本-go-design-patterns
今天小编就为大家分享一篇Golang GBK转UTF-8的例子,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
go1.8.3-golang-linux-mips-openwrt-lede,go语言1.8.3在mips芯片的openwrt路由器上运行
go语言编程,Go语言程序设计(英文版),学习 Go 语言(Golang),golang-china读书笔记
开源项目-SaturnsVoid-GoLANG-Google-Chrome-Password-Recovery.zip,GoLANG-Google-Chrome-Password-Recovery
golang-github-pmezard-go-difflib-unit-test-devel-0-0.9.git792786c.1.el7.x86_64 官方离线安装包,亲测可用
Snapshot 采用纯Golang编写的强大、可持久化,Key-Value (KV)存储
戈朗克罗斯 Docker容器可对包含cgo支持的go软件包进行交叉编译... 建立跨语言的图像docker build --build-arg GO_VERSION=1.16.2 --build-arg GOLANG_DIST_SHA=542e936b19542e62679766194364f45141fde55169db2d8d01046
go-xmlrpc - 为golang添加XML RPC支持使用go generate (generates xml parse code)
go-sh是一个golang的调用shell的库。 使用linux的人都知道shell脚本有它难以取代的优势,用2个词形容就是,简单、粗暴。但是shell有不少的坑,很容易就写的换个机器就不能使了。golang的优势很明显,写出来的代码...
华为云OBS操作SDK
build-web-application-with-golang-en. build-web-application-with-golang-en. build-web-application-with-golang-en.
gographviz - 解析golang的Graphviz DOT语言
GoQL - 用类似的SQL查询golang源代码
The-Golang-Standard-Library-by-Example-master.zip
go.vm 一个简单的虚拟机 - 编译器和解释器 - 用golang编写