Go 编程入门教程
如何开始使用这种有用的新编程语言。
您可能听说过 Go 语言。像任何新的编程语言一样,它也经历了一段时间的成熟和稳定,才变得可以用于生产应用。如今,Go 是一种成熟的语言,被用于 Web 开发、编写 DevOps 工具、网络编程和数据库。Docker、Kubernetes、Terraform 和 Ethereum 都是用 Go 编写的。Go 语言的普及速度正在加快,2017 年的采用率增长了 76%,现在已经有了 Go 用户组和 Go 会议。无论您是想增加您的专业技能,还是仅仅对学习一门新的编程语言感兴趣,都应该了解一下它。
Go 语言历史Google 的三位程序员创建了 Go 语言:Robert Griesemer、Rob Pike 和 Ken Thompson。该团队决定创建 Go 语言,是因为他们对 C++ 和 Java 感到失望,这些语言多年来变得笨重且难以使用。他们希望将乐趣和效率带回编程中。
这三位都成就斐然。Griesemer 曾参与 Google 的超快速 V8 JavaScript 引擎的开发,该引擎用于 Chrome 网页浏览器、Node.js JavaScript 运行时环境以及其他地方。Pike 和 Thompson 是创建 UNIX、C 语言和 UNIX 实用程序的贝尔实验室原始团队的成员,这导致了 GNU 实用程序和 Linux 的开发。Thompson 编写了 UNIX 的第一个版本,并创建了 B 编程语言,C 语言就是基于 B 语言开发的。后来,Thompson 和 Pike 在 Plan 9 操作系统团队工作,他们还共同定义了 UTF-8 字符编码。
为什么选择 Go?Go 语言兼具静态类型的安全性和垃圾回收,以及编译型语言的速度。对于其他语言,“编译”和“垃圾回收”往往意味着漫长的编译等待时间和运行缓慢的程序。但 Go 语言拥有闪电般快速的编译器,编译时间几乎可以忽略不计,以及现代、超高效的垃圾回收器。您将获得快速的编译时间和快速的程序。Go 语言具有简洁的语法和文法,关键字很少,这使得 Go 语言拥有像 Python、Ruby 和 JavaScript 这样的动态类型解释型语言的简洁性和乐趣。
Go 语言的设计理念是融合多种语言的优点。乍一看,Go 语言很像 C 和 Pascal(它们都是 Algol 60 的后继者)的混合体,但仔细观察,您会发现它也借鉴了许多其他语言的思想。
Go 语言被设计成一种简单易用的编译型语言,同时允许编写简洁且高效运行的程序。Go 语言缺乏冗余的功能,因此可以流畅地编程,而无需在编程时查阅语言文档。Go 语言编程快速、有趣且高效。
开始使用 Go首先,请确保您已安装 Go 语言。您可能可以使用发行版的软件包管理系统。要查找 Go 软件包,请尝试搜索 “golang”,它是 Go 的同义词。如果您无法通过这种方式安装,或者想要更新的版本,请从 https://golang.ac.cn/dl 获取 tarball,并按照该页面上的说明进行安装。
安装 Go 后,请尝试以下命令
$ go version
go version go1.10 linux/amd64
输出显示我已经在 64 位 Linux 机器上安装了 Go 1.10 版本。
希望到现在您已经产生了兴趣,并想看看一个完整的 Go 程序是什么样的。这是一个非常简单的 Go 程序,它会打印 “hello, world”
package main
import "fmt"
func main() {
fmt.Printf("hello, world\n")
}
package main
行定义了此文件所属的包。将包和函数命名为 main
会告诉 Go,这是程序执行的起点。即使整个程序中只有一个包和一个函数,您也需要定义一个 main
包和 main
函数。
在顶层,Go 源代码被组织成包。每个源文件都是包的一部分。导入包和导出函数非常简单。
下一行,import "fmt"
导入了 fmt 包。它是 Go 标准库的一部分,包含 Printf()
函数。通常您需要导入多个包。要导入 fmt
、os
和 strings
包,您可以键入以下任一代码
import "fmt"
import "os"
import "strings"
或者这样
import (
"fmt"
"os"
"strings"
)
使用括号,import
应用于括号内列出的所有内容,这节省了一些输入。您会在 Go 语言的其他地方再次看到像这样使用括号,并且 Go 语言还有其他类型的输入快捷方式。
包可以导出常量、类型、变量和函数。要导出某些内容,只需将您要导出的常量、类型、变量或函数的名称大写即可。就这么简单。
请注意,在 “hello, world” 程序中没有分号。行尾的分号是可选的。虽然这很方便,但当您刚开始学习 Go 语言时,需要注意一些事情。Go 语言的这部分语法是使用 BCPL 语言中的一种方法实现的。编译器使用一组简单的规则来“猜测”行尾是否应该有分号,并自动插入一个分号。在这种情况下,如果 main()
中的右括号在行尾,它会触发该规则,因此必须将左大括号放在 main()
后的同一行上。
这种格式在其他语言中是一种常见的做法,但在 Go 语言中,这是必需的。如果您将左大括号放在下一行,您将收到错误消息。
Go 语言的不同寻常之处在于,它要么要求,要么偏爱特定的空白格式样式。该语言并没有允许各种格式样式,而是将单一的格式样式作为其设计的一部分。程序员有很多自由来违反它,但只能在一定程度上。这要么是紧身衣,要么是天赐之物,这取决于您的偏好!许多其他语言允许的自由格式可能会导致一个迷你的巴别塔,使其他程序员难以阅读代码。Go 语言通过使单一的格式样式成为首选来避免这种情况。由于采用标准格式样式并习惯性地使用它相当容易,因此您所要做的就是编写普遍可读的代码。这公平吗?Go 语言甚至附带了一个工具,用于重新格式化您的代码,使其符合标准
$ go fmt hello.go
只有两个注意事项:您的代码必须没有语法错误才能工作,因此它不会修复我刚才描述的那种问题。此外,它会覆盖原始文件,因此如果您想保留原始文件,请在运行 go fmt
之前进行备份。
main()
函数只有一行代码来打印消息。在本例中,使用了 fmt
包中的 Printf()
函数,使其类似于用 C 语言编写 “hello, world” 程序。如果您愿意,您也可以使用以下代码
fmt.Println("hello, world")
以节省输入字符串末尾的 \n
换行符。
现在让我们编译并运行程序。首先,将 “hello, world” 源代码复制到一个名为 hello.go
的文件中。然后使用以下命令编译它
$ go build hello.go
要运行它,请使用生成的名为 hello
的可执行文件作为命令
$ hello
hello, world
作为快捷方式,您可以使用一个命令完成这两个步骤
$ go run hello.go
hello, world
这将编译并运行程序,而无需创建可执行文件。当您正在积极开发项目并且只是在进行更多编辑之前检查错误时,这非常有用。
接下来,让我们看一下 Go 语言的一些主要特性。
并发Go 语言内置的对并发的支持,以goroutine 的形式,是该语言的最佳特性之一。goroutine 类似于进程或线程,但它要轻量得多。一个 Go 程序拥有数千个活动的 goroutine 是很正常的。启动一个 goroutine 非常简单,只需
go f()
然后函数 f()
将与主程序和其他 goroutine 并发运行。Go 语言有一种允许程序的并发部分使用通道进行同步和通信的方法。通道有点像 UNIX 管道;它可以在一端写入,在另一端读取。通道的常见用途是 goroutine 指示它们何时完成。
goroutine 及其资源由 Go 运行时系统自动管理。借助 Go 语言的并发支持,很容易让多核 CPU 的所有核心和线程高效工作。
类型、方法和接口您可能想知道为什么类型和方法在同一个标题下。这是因为 Go 语言有一个简化的面向对象编程模型,它与表达性强、轻量级的类型系统协同工作。它完全避免了类和类型层次结构,因此可以在不造成混乱的情况下使用数据类型完成复杂的事情。在 Go 语言中,方法附加到用户定义的类型,而不是类、对象或其他数据结构。这是一个简单的例子
// make a new type MyInt that is an integer
type MyInt int
// attach a method to MyInt to square a number
func (n MyInt) sqr() MyInt {
return n*n
}
// make a new MyInt-type variable
// called "number" and set it to 5
var number MyInt = 5
// and now the sqr() method can be used
var square = number.sqr()
// the value of square is now 25
与此同时,Go 语言有一个名为接口的工具,允许混合类型。只要每种类型都附加了接口定义中指定的、操作所需的 method 或 methods,就可以对混合类型执行操作。
假设您创建了名为 cat
、dog
和 bird
的类型,并且每种类型都有一个名为 age()
的方法,该方法返回动物的年龄。如果您想在一个操作中将所有动物的年龄相加,您可以定义如下接口
type animal interface {
age() int
}
然后 animal
接口可以像类型一样使用,允许在计算年龄时将 cat
、dog
和 bird
类型一起处理。
考虑到 Ken Thompson 和 Rob Pike 定义了现在全球占主导地位的 Unicode UTF-8 编码,Go 语言对 UTF-8 有良好的支持可能不会让您感到惊讶。如果您从未使用过 Unicode 并且不想为此烦恼,请不要担心;UTF-8 是 ASCII 的超集。这意味着您可以继续使用 ASCII 进行编程,并忽略 Go 语言的 Unicode 支持,一切都会运行良好。
实际上,所有源代码都被 Go 编译器和工具视为 UTF-8。如果您的系统配置正确,允许您输入和显示 UTF-8 字符,您可以在 Go 源代码文件名、命令行参数以及 Go 源代码中用于文字字符串以及变量、函数、类型和常量的名称。
在图 1 中,您可以看到一个葡萄牙语的 “hello, world” 程序,就像巴西程序员可能编写的那样。

图 1. 葡萄牙语的 Go “Hello, World” 程序
除了在这些方面支持 Unicode 之外,Go 语言的标准库中还有三个包用于处理涉及 Unicode 的更复杂的问题。
到现在,您可能明白为什么 Go 程序员对这门语言如此热情了。不仅仅是因为 Go 语言有这么多优点,而且所有这些优点都包含在一种旨在避免过度复杂化的语言中。这是一个整体大于部分之和的真正好例子。
资源