上次说到 hexdump 指定二进制文件格式以及打印的方式不好用,所以用 Go 写了一个替代,起名叫 bprint (想不到更好的名字了)。代码以及使用说明都在 github 上。这个工具跟 hexdump 的 format string 最大的差别在于把二进制文件格式和打印方式分开来指定,个人觉得这种方式使用起来更加方便。
Go 的确是个不错的语言,标准库很多函数的接口设计得很好用。说下写这个小工具时的一点感受吧。
写这个程序时要处理二进制文件。Go 是强类型的,没法像 C 一样读一块内存以后随便当成各种类型的整数,必须用 encoding.binary
这个库提供的函数来读取各种类型的整数。这一点使得 bprint 的性能肯定没法跟 C 版本的相比。
另一方面强类型使得 Go printf 一类函数的 format string 不需要指定整数大小,有符号无符号整数可以使用相同的字符指代,因为这些信息从参数的类型里可以直接得到。Go 的 printf 类函数用起来很舒服。
标准库的正则表达式用起来也还算方便(当然还是没法跟 Ruby 这样内建正则表达式支持的语言相比),其 API 命名很有意思也很值得学习。用来做字符串匹配的函数名匹配于下面这个正则表达式:
Find(All)?(String)?(Submatch)?(Index)?
String
表示函数接受string
类型的参数,没有这个名字的接受[]byte
为参数Submatch
表示返回值是否包含匹配的各个 groupIndex
则表示返回匹配内容还是返回匹配项的起止索引All
表示是否返回所有匹配内容
这种命名方式使得我们看函数名就能知道函数的用途,所以很容易找到自己需要的函数。(这让我想起 Joel Spolsky 的文章 Making Wrong Code Look Wrong 里提到的正确的匈牙利命名法。)貌似标准库的正则表达式是把 Russ Cox 的 RE2 用 Go 重新实现了一遍,有空的时候想看下它的代码。
另外 flag
库用来做命令行选项的解析真是比 C 的 getopt
好用太多。
Go 没有 exception,类似 C 通过返回值来表示错误,不过由于有 multi return value,所以 Go 使用这种方式比 C 方便一些。这种错误处理的方式的确会使代码看起来不那么干净,但不会带来 exception 的问题。(Exception 本质上是一种 non-local goto,其存在的问题可以看 Raymond Chen 的文章 Cleaner, more elegant, and harder to recognize)。
go
这个工具使得我们可以不用写 Makefile,自动格式化代码,方便的编写和执行测试,这些特性都使得我们可以更加专注于写代码而不用跟编译构建系统做斗争。go
这个工具的存在让我体会到了下面这句话的含义
“Go is not meant to innovate programming theory. It’s meant to innovate programming practice.” — Samuel Tesla
Go 的确是一个很好的 C 的替代,目前性能还不是非常好,但相信未来随着编译器的进步会有提升。暂时还没有用到 Go concurrency 的特性,但看起来也是很诱人。
如果对 Go 有兴趣,想知道 Rob Pike, Ken Thompson 还有 Robert Griesemer 为什么发明 Go 以及 Go 的设计思想,推荐 Rob Pike 的文章 Less is exponentially more。