1.1.3  Go 语言的类型系统  

Go 语言提供了灵活的、无继承的类型系统,无需降低运行性能就能最大程度上复用代码。这个类型系统依然支持面向对象开发,但避免了传统面向对象的问题。如果你曾经在复杂的 Java 和 C++程序上花数周时间考虑如何抽象类和接口,你就能意识到 Go 语言的类型系统有多么简单。

Go 开发者使用组合(composition)设计模式,只需简单地将一个类型嵌入到另一个类型,就能复用所有的功能。其他语言也能使用组合,但是不得不和继承绑在一起使用,结果使整个用法非常复杂,很难使用。在 Go 语言中,一个类型由其他更微小的类型组合而成,避免了传统的基于继承的模型。  

另外,Go 语言还具有独特的接口实现机制,允许用户对行为进行建模,而不是对类型进行建模。在 Go 语言中,不需要声明某个类型实现了某个接口,编译器会判断一个类型的实例是否符合正在使用的接口。Go 标准库里的很多接口都非常简单,只开放几个函数。从实践上讲,尤其对那些使用类似 Java 的面向对象语言的人来说,需要一些时间才能习惯这个特性。  

1.类型简单  

Go 语言不仅有类似int和string这样的内置类型,还支持用户定义的类型。在 Go 语言中,用户定义的类型通常包含一组带类型的字段,用于存储数据。Go 语言的用户定义的类型看起来和 C 语言的结构很像,用起来也很相似。不过 Go 语言的类型可以声明操作该类型数据的方

法。传统语言使用继承来扩展结构——Client 继承自 User,User 继承自 Entity,Go 语言与此不同,

Go 开发者构建更小的类型——Customer 和 Admin,然后把这些小类型组合成更大的类型。图 1-4 展示了继承和组合之间的不同。  

2.Go 接口对一组行为建模  

接口用于描述类型的行为。如果一个类型的实例实现了一个接口,意味着这个实例可以执行

 

6  第 1 章 关于 Go 语言的介绍  

一组特定的行为。你甚至不需要去声明这个实例实现某个接口,只需要实现这组行为就好。其他的语言把这个特性叫作鸭子类型——如果它叫起来像鸭子,那它就可能是只鸭子。Go 语言的接口也是这么做的。在 Go 语言中,如果一个类型实现了一个接口的所有方法,那么这个类型的实例就可以存储在这个接口类型的实例中,不需要额外声明。  

 

图 1-4  继承和组合的对比  

在类似 Java 这种严格的面向对象语言中,所有的设计都围绕接口展开。在编码前,用户经常不得不思考一个庞大的继承链。下面是一个 Java 接口的例子:  

interface User {  public void login();  

public void logout();  

}  

在 Java 中要实现这个接口,要求用户的类必须满足User接口里的所有约束,并且显式声明这个类实现了这个接口。而 Go 语言的接口一般只会描述一个单一的动作。在 Go 语言中,最常使用的接口之一是io.Reader。这个接口提供了一个简单的方法,用来声明一个类型有数据可以读取。标准库内的其他函数都能理解这个接口。这个接口的定义如下:  

type Reader interface {  

Read(p []byte) (n int, err error)  

}  

为了实现io.Reader这个接口,你只需要实现一个Read方法,这个方法接受一个byte 切片,返回一个整数和可能出现的错误。  

这和传统的面向对象编程语言的接口系统有本质的区别。Go 语言的接口更小,只倾向于定义一个单一的动作。实际使用中,这更有利于使用组合来复用代码。用户几乎可以给所有包含数据的类型实现 io.Reader 接口,然后把这个类型的实例传给任意一个知道如何读取

io.Reader的 Go 函数。  

Go 语言的整个网络库都使用了io.Reader接口,这样可以将程序的功能和不同网络的实现分离。这样的接口用起来有趣、优雅且自由。文件、缓冲区、套接字以及其他的数据源都实现了io.Reader接口。使用同一个接口,可以高效地操作数据,而不用考虑到底数据来自哪里。  

 

1.1.4  内存管理  

不当的内存管理会导致程序崩溃或者内存泄漏,甚至让整个操作系统崩溃。Go 语言拥有现代化的垃圾回收机制,能帮你解决这个难题。在其他系统语言(如 C 或者 C++)中,使用内存前要先分配这段内存,而且使用完毕后要将其释放掉。哪怕只做错了一件事,都可能导致程序崩溃或者内存泄漏。可惜,追踪内存是否还被使用本身就是十分艰难的事情,而要想支持多线程和高并发,更是让这件事难上加难。虽然 Go 语言的垃圾回收会有一些额外的开销,但是编程时,能显著降低开发难度。Go 语言把无趣的内存管理交给专业的编译器去做,而让程序员专注于更有趣的事情。  

1.2  你好,Go  

感受一门语言最简单的方法就是实践。让我们看看用 Go 语言如何编写经典的 Hello  

World!应用程序:

Go 程序都组织成包。  

package main  import语句用于导入外部代码。标准库中的fmt包用于格式化并输出数据。

import "fmt"  

func main() {  像 C 语言一样,main函  fmt.Println("Hello world!") 数是程序执行的入口。  

}  

运行这个示例程序后会在屏幕上输出我们熟悉的一句话。但是怎么运行呢?无须在机器上安装 Go 语言,在浏览器中就可以使用几乎所有 Go 语言的功能。  

介绍 Go Playground  

Go Playground 允许在浏览器里编辑并运行 Go 语言代码。在浏览器中打开 http://play.golang.org。浏览器里展示的代码是可编辑的(见图 1-5)。点击 Run,看看会发生什么。  

可以把输出的问候文字改成别的语言。试着改动 fmt.Println()里面的文字,然后再次点击 Run。  

分享 Go 代码  Go 开发者使用 Playground 分享他们的想法,测试理论,或者调试代码。你也可以这么做。每次使用 Playground 创建一个新程序之后,可以点击 Share 得到一个用于分享的网址。任何人都能打开这个链接。试试

要给想要学习写东西或者寻求帮助的同事或者朋友演示某个想法时,Go Playground 是非常好的方式。在 Go 语言的 IRC 频道、Slack 群组、邮件列表和 Go 开发者发送的无数邮件里,用户都能看到创建、修改和分享 Go Playground 上的程序。