先大概说下为什么用 Golang。我是一个对语言有洁癖的人,曾经是一个C+Python 的坚定呐喊者,最常说的一句话就是,只要熟练这两种,什么情况都能应付,根本不用 Java 和 C++(纯指我所在的领域)。核心代码用C,速度快,需要记的语言细节少;外围用 Python glue,灵活,简洁,任何模块都容易上手,绝配。Java 的繁琐,C++ 的无数无用的特性,都让我只在不得不用的时候才去用。Objective-C 是另一个我欣赏的语言,问题是不跨平台,过于封闭。
可惜的是,在这个节奏极快的时代,不是所有情况下都适合上C。之前有一个项目也是类似的架构和规模,为了节省时间,当初几乎没有服务器平台编程经验的我,在服务器端选择用 Django+Apache+MySQL 做,成熟,社区活跃,又是 Python 作为主要开发语言,这些都是这个选择的原因。说实话,几个月过去后,回首看,这不是一个愉快的经历。Django 是一个好架构,大而全,而大而全有时也就意味着臃肿,五花八门的配置,过紧的模块耦合对引入第三方工具限制颇多,自带的 ORM 又不好用。之前从来没有搞过服务器配置的我,对 Apache 的配置和效率所带来的琐碎的东西也头疼。总的来说这个部分花了我很多时间,有新手学习服务器编程的必经过程,也有折腾 Django 和 Apache 没必要的时间浪费,很大部分上抵消了 Python 带来的快速开发的灵活性。而一旦服务器上线,动态语言带来的一些 bug 又会让人头疼。对于普通高校实验室这种没有完善的服务器调试的条件,基本就是改了就上线用,有些隐蔽 bug 到某些条件分支才会触发,一旦在运行中途出问题,改起来也麻烦。
从那时起,我就特别想,要是有一种语言能把 C 和 Python 的优点结合起来,也就是说
- 速度快,高性能
- 简洁明了,需要记的语言细节少,开发迅速(C)
- 灵活,开发快速,类 Python 的 list,map 等常用数据结构支持(Python)
- 完善的模块支持,模块也容易上手(Python)
- 对程序员友好的并行架构(Erlang)
- 安全,绝大部分问题能消灭在 compile time 中(C minus pointer)
那基本就是系统级和网络级编程最对我胃口的语言了。然后我就找到了 Go。
Golang 是一个新语言,截至目前为止,第一版正式版还没有发布。Golang 的设计者是 Robert Griesemer, Rob Pike 和 Ken Thompson,当年设计 C 和 Unix,后来的 Plan9 团队中的人 。Golang 的设计理念很明确,就是将动态类型语言的编程容易度和静态类型语言的安全效率结合起来。如果你想更深入了解 Golang 的发展历史以及完整的目标,请参考 Golang FAQ。
当然,Golang 吸引我的地方,不是因为其是 Google 出品,也不是因为其设计者皆为大牛,而是因为,Golang 真的做到了它所宣称的目标。Golang 就如同 C 和 Python 中间的完美结合,如果你是 Python 爱好者,又追求代码的速度和并行化,那么简单说,Golang 就是为你设计的。Golang 有很浓厚的C的遗风,尽量屏蔽 C++ 和 Java 的影响,比如没有独立的 OO 体系(并不是说不能 OO),一切以 struct 为中心,没有 exceptions (Oh yes!),仍然有指针,等等。但是,Golang 又吸取了很多新语言的精华,并带有自己独特的设计。比如:
1. 保留但大幅度简化指针
Golang 保留着C中值和指针的区别,但是对于指针繁琐用法进行了大量的简化,引入引用的概念。所以在 Golang 中,你几乎不用担心会因为直接操作内寸而引起各式各样的错误。
2. 多参数返回
还记得在C里面为了回馈多个参数,不得不开辟几段指针传到目标函数中让其操作么?在 Go 里面这是完全不必要的。而且多参数的支持让 Go 无需使用繁琐的 exceptions 体系,一个函数可以返回期待的返回值加上 error,调用函数后立刻处理错误信息,清晰明了。
3. Array, slice, map 等内置基本数据结构
如果你习惯了 Python 中简洁的 list 和 dict 操作,在 Golang 中,你不会感到孤单。一切都是那么熟悉,而且更加高效。如果你是 C++ 程序员,你会发现你又找到了 STL 的 vector 和 map 这对朋友。
4. Interface
Golang 最让人赞叹不易的特性,就是 interface 的设计。任何数据结构,只要实现了 interface 所定义的函数,自动就 implement 了这个 interface,没有像 Java 那样冗长的 class 申明,提供了灵活太多的设计度和 OO 抽象度,让你的代码也非常干净。千万不要以为你习惯了 Java 那种一条一条加 implements 的方式,感觉还行,等接口的设计越来越复杂的时候,无数 Bug 正在后面等着你。
同时,正因为如此,Golang 的 interface 可以用来表示任何 generic 的东西,比如一个空的 interface,可以是 string 可以是 int,可以是任何数据类型,因为这些数据类型都不需要实现任何函数,自然就满足空 interface 的定义了。加上 Golang 的 type assertion,可以提供一般动态语言才有的 duck typing 特性, 而仍然能在 compile 中捕捉明显的错误。
5. OO
Golang 本质上不是面向对象语言,它还是过程化的。但是,在 Golang 中, 你可以很轻易的做大部分你在别的 OO 语言中能做的事,用更简单清晰的逻辑。是的,在这里,不需要 class,仍然可以继承,仍然可以多态,但是速度却快得多。因为本质上,OO 在 Golang 中,就是普通的 struct 操作。
6. Goroutine
这个几乎算是 Golang 的招牌特性之一了,我也不想多提。如果你完全不了解 Goroutine,那么你只需要知道,这玩意是超级轻量级的类似线程的东西,但通过它,你不需要复杂的线程操作锁操作,不需要 care 调度,就能玩转基本的并行程序。在 Golang 里,触发一个 routine 和 erlang spawn 一样简单。基本上要掌握 Golang,以 Goroutine 和 channel 为核心的内存模型是必须要懂的。不过请放心,真的非常简单。
7. 更多现代的特性
和C比较,Golang 完全就是一门现代化语言,原生支持的 Unicode, garbage collection, Closures (是的,和 functional programming language 类似), function 是 first class object,等等等等。
看到这里,你可能会发现,我用了很多轻易,简单,快速之类的形容词来形容 Golang 的特点。我想说的是,一点都不夸张,连 Golang 的入门学习到提高,都比别的语言门槛低太多太多。在大部分人都有C的背景的时代,对于 Golang,从入门到能够上手做项目,最多不过半个月。Golang 给人的感觉就是太直接了,什么都直接,读源代码直接,写自己的代码也直接。
有朋友要抗议了,你把 Golang 吹的这么好,难道它就没有缺点?有,当然有,不过和它的优点比,我觉得很多缺点都是因为整个语言太新,不成熟,随着时间的推移都能得到解决,相比之下都能忍了。如果你希望进一步了解 Golang 的优缺点,可以参考以下 yufeng 写的这篇文章,系统编程语言明日之星—Go(http://blog.yufeng.info/Go.pdf)。
还有朋友要说,Golang 这么好,为什么没人用?我想说,眼界放开点,这个世界精彩的东西比你想象的多。Golang 被 Google 用于 Youtube 的数据库,被越来越多的国外公司(大部分创业公司)用于后端开发,甚至在天朝,也有完全用 Golang 做服务开发的云应用公司了。可以说,随着 Go 1 即将到来的正式推出,Golang 的使用范围,应该会越来越广。
好,总结时间
如果你是 Python 和动态语言狂热爱好者,Go 不一定能给你带来很大的惊喜,这纯粹取决于你的项目性质,考虑到 Python 目前在很多地方都用C做核心运算,速度在大部分情况下都不是大问题。scalability 是一个问题,但并不是人人都会遇到的。
如果你是C爱好者,强烈建议你学习和使用 Go。Go 可以调用 C/C++ 程序,又提供了太多的便利,速度上稍有牺牲,但并不大。在绝大部分场景下 Go 能给你带来媲美C的性能,而对于某些确实性能过于关键的场合,也可以通过 cgo 让 Go 和C搭配。
如果你是 Java 爱好者,除非你是做 Android 这种不得不用 Java 的平台,否则也建议你尝试学习 Go,这个开发上感觉的差异如同比较开载着 1 吨石头的拖拉机和开保时捷 911 那么明显,而 Java 能给你的,Go 能给得更好。
如果你是 C++ 爱好者,!@#$%^&*,恭喜你,至少你的智商应该是没问题的。人生苦短,赶紧脱离 C++ 这个苦海吧。你用来学 89 个 C++ 高级特性的时间,估计已经用 Go 写了 64 个开源项目了。
如果你是像我一样的 C 和 Python 的爱好者,对动态语言又没有特殊的热爱……我还需要说什么呢?
废话不多说,让我们荡起双桨,去遨游 Golang 的海洋吧。锻炼网址:http://tour.golangtc.com/
GO GO GO!!!练习1:map
实现 `WordCount`。它应当返回一个含有 s
中每个 “词” 个数的 map。函数 wc.Test
针对这个函数执行一个测试用例,并输出成功还是失败。
你会发现 strings.Fields 很有帮助。
代码:
package main import ( "code.google.com/p/go-tour/wc" "strings" ) func WordCount(s string) map[string]int { s_array := strings.Fields(s) m := make(map[string]int) for i := 0; i < len(s_array); i++ { _, ok := m[s_array[i]] if ok == false { m[s_array[i]] = 1 } else { m[s_array[i]]++ } } return m } func main() { wc.Test(WordCount) }
练习2:斐波纳契闭包
现在来通过函数做些有趣的事情。
实现一个 fibonacci
函数,返回一个函数(一个闭包)可以返回连续的斐波纳契数。
代码:
package main import "fmt" // fibonacci 函数会返回一个返回 int 的函数。 func fibonacci() func() int { var pre, next, sum int pre = 0 next = 1 count := -1 return func() int { count++ if count < 2 { return count } sum = pre + next pre = next next = sum return sum } } func main() { f := fibonacci() for i := 0; i < 10; i++ { fmt.Println(f()) } }