这篇文章是我看了《Rob Pike谈Google Go:并发,Type System,内存管理和GC》这后的一个总结,原始的访谈文章请点击这里:Rob Pike谈Google Go:并发,Type System,内存管理和GC 。
虽然我个人不是很喜欢Go的语法,但是看了这个访谈,我还是被Go的一些特性所吸引。世界上没有包治百病的灵丹妙药,不存在所谓的“银弹”,当我在使用Java的时候,Go的这些特性正是我苦苦找寻的东西:
Go拥有非常快的编译器和编译速度
Go目前为止有两个编译器,一个是按照Plan 9 风格编写的,另一个是Gcc Go,尽管两个编译器相较其他语言的编译器已经非常快了,但是其中Plan 9风格的速度比Gcc Go还要快上5倍。
Rob Pike解释了Go编译器快的主要原因。传统语言比如C或者C++,它们本身并不强制检查依赖,所以每一次编译都必须分析代码以便清楚程序依赖的函数是怎样的,这样就会重复编译某些被不同模块依赖的相同的类或者头文件;而Go有一个严格的依赖模型,它有一些叫做包(packages)的东西,很像Java类文件或着类似的东西,或者函数库什么的,虽然他们并不相同,但基本思路是一样的。当A依赖B,B又依赖C时,那么首先会编译C,然后是B和A;但是如果A依赖B,但是A并不直接依赖于C,而是存在依赖传递,这时会把所有B需要从C拿到的信息放在B的对象代码里。这样,当编译A的时候,就不需要再管C了。于是事情就非常简单了:在编译程序时,只需将类型信息沿着依赖关系树向上遍历即可,如果到达树的顶端,则只需编译紧邻的依赖,而不用管其它层级的依赖了。
Rob Pike说像Go现在的编译器在大型系统中进行编译,速度与C++相比是秒级别和分钟级别的对比关系。可见Go编译速度只快。
Go的类型系统
Go的类型有整数、字符串、struct数据结构、以及数组(array),Go里称之切片(slice)。Go里没有类,只有struct。Go里的方法比Java中的方法更加宽泛,它可以加到任何自己定义的类型上,但是不像Ruby,它不能破坏已经定义好的类型,因此Go在这方面更加安全。Go可以使用type关键字来定义一个基于现有类型的类型,它不同于C中的别名,比如type Day int,这里定义的Day拥有int的结构特性,但是可以让我们加入自己的方法集。
值类型和指针
在Go里,任何类型都是值类型,所有东西都是按值调用的。Go中也可以使用指针,但是和C++的指针不同,Go中的指针有更多的限制,并且是类型安全的,没有指针运算,我们无法将指针移到对象之外,也不能欺骗编译器。
不用implements的结构
Go里有接口,同样也是一组方法的集合。但是Go里面的类型不用去声明implements(实现)某个接口,当某个类型定义了某个接口中的所有方法时,这个类型就implements(实现)了这个接口。Rob Pike解释说,这么设计可以让开发人员更关注于要做什么东西,而不是去实现什么接口。他举了一个例子:比如有两个struct都实现了一些非常有用的小子集中的相关方法,这时有办法能够操作这两个structs中的任意一个就显得非常有用了。这样我们就可以声明一个接口,然后什么都不用管了,即使这些方法是在别人的代码中实现的也没问题,虽然我们不能编辑这些代码。如果是Java,这些代码必须要声明实现这个的接口,在某种意义上,实现是单向的。然而在Go里,实现是双向的。这是一种鸭子类型系统 。
没有类,怎么实现类似于继承的功能
Go的struct类型可以嵌套其他已经存在的类型,嵌套之后可以获得被嵌入者的数据和它的方法。关于可能会出现的命名冲突,Go是静态处理这一问题的。其规则是,如果有多层嵌入,则最高层优先;如果同一层有两个相同的名字或相同的方法,Go会给出一个简单的静态错误。我们不用自己检查,只需留意这个错误即可。命名冲突是静态检查的,而且规则非常简单,在实践中命名冲突发生的也并不多。
Go中的Goroutine
Goroutine在Go中可以看作是一个非常轻量级的小线程。Goroutine在创建的时候,会在堆上为其分配大小4K的栈,随后这个栈会根据实际使用自动增大或者缩小,我们不用担心会溢出。
Goroutine之间可以通过同步通道和异步通道进行通信,通信的消息是任意的,甚至可以把通道当作消息发送出去。同步通道是没有缓存的,只有异步通道才需要缓存。
Go的GC效率
Go是系统级的语言,但是它提供了GC功能,关于GC的效率,Rob Pike表示说他们正在不断的进行研究,因为在这个领域还有许多的工作需要做,他们不认为将来会将GC的延迟降为0,但是他们会尽可能的去提高GC的效率。
有疑问加站长微信联系(非本文作者)