Go
(又称[4])是Google开发的一种静态强类型、编译型、,并具有垃圾回收功能的编程语言。
![]() | |
编译型,,结构化,指令式 | |
设计者 | 罗伯特·格瑞史莫 罗勃·派克 肯·汤普逊 |
实作者 | |
2009年11月10日 | |
当前版本 |
|
操作系统 | Linux、macOS、FreeBSD、Windows |
许可证 | BSD |
文档扩展名 | .go |
网站 | https://go.dev/ https://golang.google.cn/[2] |
主要实作产品 | |
gc (8g,6g,5g),gccgo | |
启发语言 | |
C、Oberon、Limbo、Newsqueak[3] |

罗伯特·格瑞史莫、罗勃·派克及肯·汤普逊于2007年9月开始设计Go,[3]稍后伊恩·兰斯·泰勒()、拉斯·考克斯()加入项目。Go是基于Inferno操作系统所开发的。[5]Go于2009年11月正式宣布推出,成为开放原代码项目,支持Linux、macOS、Windows等操作系统。[6]
在2016年,Go被软件评价公司TIOBE选为「TIOBE 2016年最佳语言」。[7]
目前,Go每半年发布一个二级版本(即从升级到)。
描述
Go的语法接近C语言,但对于变量的声明有所不同。Go支持垃圾回收功能。Go的并行计算模型是以东尼·霍尔的通信顺序进程(CSP)为基础,采取类似模型的其他语言包括Occam和Limbo[3],Go也具有这个模型的特征,比如信道传输。通过goroutine和信道等并行构造可以建造线程池和管道等[8]。在1.8版本中开放插件(Plugin)的支持,这意味着现在能从Go中动态加载部分函数。
与C++相比,Go并不包括如枚举、异常处理、继承、泛型(此功能在go1.18中加入)、断言、虚函数等功能,但增加了切片(Slice) 型、并发、管道、垃圾回收、接口等特性的语言级支持[3]。对于断言的存在,则持负面态度,同时也为自己不提供类型继承来辩护。
批评
尽管 Go 的官方与支持者对于语言中不使用泛型与异常处理有着大量辩解说词,但批评声也从未停过。在发表 Go 语言 2.0 的草案时,官方称没有泛型、异常处理与模块对于 Go 发展造成很大的阻碍[9],等同承认 Go 没有这些特色是设计错误。
Go 的垃圾回收机制一直被人诟病,直到 1.8 版本垃圾回收的功能才较为稳定。然而尽管如此,Go 的垃圾回收还是远远落后 JVM 的 G1 和 ZGC。Discord 的研发团队在2020年初甚至发表一篇博客,宣布把其中一个服务由从 Go 转移至 Rust,理由是 Go 的垃圾回收会导致每2分钟出现一次卡顿,并且 Discord 研发团队测试了 Go 语言的1.8、1.9、1.10版本这个问题都没有改善[10]。
历史
2007年,Google设计Go,目的在于提高在多核、网络机器(networked machines)、大型代码库(codebases)的情况下的开发效率。[11]当时在Google,设计师们想要解决其他语言使用中的缺点,但是仍保留他们的优点。[12]
设计师们主要受他们之间流传的“不要像C++”启发。[14][15][16]
Go于2009年11月正式宣布推出,[17]版本1.0在2012年3月发布。[18][19]之后,Go广泛应用于Google的产品[20]以及许多其他组织和开源项目。
在2016年11月,Go(一种无衬线体)和Go Mono 字体(一种等宽字体)分别由设计师查尔斯·比格洛和克莉丝·荷姆斯发布。两种字体均采用了WGL4,并且依照着 DIN 1450 标准,可清晰地使用了 large x-height 和 letterforms 。[21][22]
在2018年8月,原生的图标更换了。待描述完整 然而,Gopher mascot 仍旧命相同的名字。[23]
在2018年8月,Go的主要贡献者发布了两个关于语言新功能的“草稿设计——泛型和异常处理,同时寻求Go用户的反馈。[24][25]Go 由于在1.x时,缺少对泛型编程的支持和冗长的异常处理而备受批评。
版本历史
Go 1 保证语言规范[26]和标准库的主要部分兼容。直到目前的 Go 1.20 发布[27],所有版本都履行了这个承诺。 每个主要的 Go 发布版本会受到支持,直到出现两个新的主要版本为止。[28]
Release | Status | Release date | Maintenance end |
---|---|---|---|
go1 | End-of-Life | 2012-03-28 | 2013-12-01 |
go1.1 | End-of-Life | 2013-05-13 | 2014-06-18 |
go1.2 | End-of-Life | 2013-12-01 | 2014-12-10 |
go1.3 | End-of-Life | 2014-06-18 | 2015-08-19 |
go1.4 | End-of-Life | 2014-12-10 | 2016-02-17 |
go1.5 | End-of-Life | 2015-08-19 | 2016-08-15 |
go1.6 | End-of-Life | 2016-02-17 | 2017-02-16 |
go1.7 | End-of-Life | 2016-08-15 | 2017-08-24 |
go1.8 | End-of-Life | 2017-02-16 | 2018-02-16 |
go1.9 | End-of-Life | 2017-08-24 | 2018-08-24 |
go1.10 | End-of-Life | 2018-02-16 | 2019-02-25 |
go1.11 | End-of-Life | 2018-08-24 | 2019-09-03 |
go1.12 | End-of-Life | 2019-02-25 | 2020-02-25 |
go1.13 | End-of-Life | 2019-09-03 | 2020-08-11 |
go1.14 | End-of-Life | 2020-02-25 | 2021-02-16 |
go1.15 | End-of-Life | 2020-08-11 | 2021-08-16 |
go1.16 | End-of-Life | 2021-02-16 | 2022-03-15 |
go1.17 | End-of-Life | 2021-08-16 | 2022-08-02 |
go1.18 | End-of-Life | 2022-03-15 | 2023-02-01 |
go1.19 | End-of-Life | 2022-08-02 | 2023-08-08 |
go1.20 | Maintenance | 2023-02-01 | Q1 2024 |
go1.21 | Current | 2023-08-08 | Q3 2024 |
格式: 旧版本 旧版本,仍被支持 当前版本 未来版本 |
代码示例
Hello World
下面是用Go写成的Hello World进程:
package main
import "fmt"
func main() {
fmt.Println("Hello, World")
}
HTTP网页服务器
通过Go仅需几行代码就完成HTTP网页服务器的实现:
package main
import (
"io"
"net/http"
)
func hello(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "Hello world!")
}
func main() {
http.HandleFunc("/", hello)
http.ListenAndServe(":8000", nil)
}
Echo命令进程
下面的例子说明了怎样用Go去实现一个像Unix中的Echo命令进程[29]:
package main
import (
"os"
"flag"
)
var omitNewline = flag.Bool("n", false, "don't print final newline")
const (
Space = " "
Newline = "\n"
)
func main() {
flag.Parse() // Scans the arg list and sets up flags
var s string = ""
for i := 0; i < flag.NArg(); i++ {
if i > 0 {
s += Space
}
s += flag.Arg(i)
}
if !*omitNewline {
s += Newline
}
os.Stdout.WriteString(s)
}
语言特征
撰写风格
Go有定义如下的撰写风格:
- 每行程序结束后不需要撰写分号
;
。 - 大括号
{
不能够换行放置。 if
判断式和for
循环不需要以小括号包覆起来。- 使用 tab 做排版
除了第二点外(换行会产生编译错误),在不符合上述规定时,仍旧可以编译,但使用了内置gofmt工具后,会自动整理代码,使之符合规定的撰写风格。
module
Go 采用 module 的概念(于 go1.11才开始激活[30],旧版本请参阅工作区),每个项目都是一个 module ,而每个 module 底下会有个 go.mod
的文件,来管理该 module 所引用的外部库、开发版本……等等。
一个 module 的文件夹目录可能如下
go.mod
hello/
hello.go
outyet/
main.go
main_test.go # 测试用的程序
stringutil/
reverse.go
reverse_test.go # 测试用的程序
bmp/
reader.go
writer.go
然后 go.mod 的内容可能为
module example.org/go-mod-sample
go 1.11
require (
github.com/golang/example v0.0.0-20220412213650-2e68773dfca0
golang.org/x/image v0.1.0
)
工作区
Go的工作区位于GOPATH
,其目录结构如下[31]:
src
pkg
bin
三个目录的用途分别为
目录 | 用途 |
---|---|
src | 引用的外部库 |
pkg | 编译时,生成的对象文档 |
bin | 编译后的程序 |
举例来说,整个项目目录可能会如下:
bin/
hello # 生成的运行档
outyet # 生成的运行档
pkg/
linux_amd64/
github.com/golang/example/
stringutil.a # 编译时,生成的对象文件
src/
github.com/golang/example/
.git/ # 外部 Git 库的诠释数据
hello/
hello.go # Git 库的代码
outyet/
main.go # Git 库的代码
main_test.go # Git 库的代码(测试用的程序)
stringutil/
reverse.go # Git 库的代码
reverse_test.go # Git 库的代码(测试用的程序)
golang.org/x/image/
.git/ # 外部 Git 库的诠释数据
bmp/
reader.go # Git 库的代码
writer.go # Git 库的代码
轻型协程
Go的主要特色在于易于使用的并行设计,叫做Goroutine,通过Goroutine能够让程序以异步的方式运行,而不需要担心一个函数导致程序中断,因此Go也非常地适合网络服务。假设有个程序,里面有两个函数:
func main() {
// 假设 loop 是一个会重复运行十次的循环函数。
// 循环运行完毕才会往下运行。
loop()
// 运行另一个循环。
loop()
}
这个时候通过Go让其中一个函数同步运行,如此就不需要等待该函数运行完后才能运行下一个函数。
func main() {
// 通过 `go`,我们可以把这个函数同步运行,
// 如此一来这个函数就不会阻塞主程序的运行。
go loop()
// 运行另一个循环。
loop()
}
Goroutine是类似线程的概念,属于纤程(区别于协程和线程)。线程属于系统层面,通常来说创建一个新的线程会消耗较多的资源且管理不易;而协程的主要作用是提供在一个线程内的并发性,却不能利用多个处理器线程。而 Goroutine就像轻量级的线程,一个Go程序可以运行超过数万个 Goroutine[32],并且这些性能都是原生级的,随时都能够关闭、结束,且运行在多个处理器线程上。一个内核里面可以有多个Goroutine,通过GOMAXPROCS参数你能够限制Gorotuine可以占用几个系统线程来避免失控。
在内置的官方套件中也不时能够看见Goroutine的应用,像是net/http中用来监听网络服务的函数实际上是创建一个不断运行循环的Goroutine;同时搭配了epoll 等IO多路复用机制维护Goroutine的事件循环。
编译器
当前有两个Go编译器分支,分别为官方编译器gc和gccgo。官方编译器在初期使用C写成,后用Go重写从而实现自举[33]。Gccgo是一个使用标准GCC作为后端的Go编译器[34]。
官方编译器支持跨平台编译(但不支持CGO),允许将原始码编译为可在目标系统、架构上执行的二进制文档。
参考文献
- .
- . [2020-09-14]. (原始内容存档于2021-08-14).
- . [2009-11-12]. (原始内容存档于2013-01-02).
- . [2018-05-07]. (原始内容存档于2020-11-28).
- . [2009-11-20]. (原始内容存档于2010-08-02).
- . [2009-11-12]. (原始内容存档于2012-03-20).
- . [2018-09-17]. (原始内容存档于2018-09-17).
- . golang.org. [2020-05-07]. (原始内容存档于2021-02-05).
- . [2021-03-15]. (原始内容存档于2021-01-26).
- . [2021-03-15]. (原始内容存档于2022-05-11).
- . [2018-10-08]. (原始内容存档于2021-01-25).
- Pike, Rob. . Stanford EE Computer Systems Colloquium. Stanford University. 2010-04-28 [2020-01-14]. (原始内容存档于2014-06-12). Video available (页面存档备份,存于).
- . golang.org. [2016-02-26]. (原始内容存档于2017-02-25).
- Andrew Binstock. . 2011-05-18 [2014-02-07]. (原始内容存档于2014-03-13).
- Pike, Rob. . 2012 [2020-01-14]. (原始内容存档于2016-03-21).
- Robert Griesemer. . 2015 [2020-01-14]. (原始内容存档于2017-01-16).
- Griesemer, Robert; Pike, Rob; Thompson, Ken; Taylor, Ian; Cox, Russ; Kim, Jini; Langley, Adam. . Google Open Source. Google. [2018-05-17]. (原始内容存档于2021-01-26).
- Shankland, Stephen. . News. CNet (CBS Interactive Inc). March 30, 2012 [2017-08-06]. (原始内容存档于2020-11-25).
Google has released version 1 of its Go programming language, an ambitious attempt to improve upon giants of the lower-level programming world such as C and C++.
- . [2014-12-11]. (原始内容存档于2017-02-17).
- . [2013-03-09]. (原始内容存档于2017-02-25).
- . Go. 2016-11-16 [2019-03-12]. (原始内容存档于2019-07-31).
- . GitHub. Google. [2019-04-02]. (原始内容存档于2019-07-31).
- . blog.golang.org. [2018-11-09]. (原始内容存档于2020-11-25).
- . [2018-09-12]. (原始内容存档于2021-01-26).
- . 2018-08-28 [2020-01-14]. (原始内容存档于2021-01-31).
- . golang.org. [2023-04-12]. (原始内容存档于2017-10-02).
- . go.dev. [2023-04-12]. (原始内容存档于2023-05-30).
- . golang.org. [2023-04-12]. (原始内容存档于2017-02-17).
- . [2009-11-20]. (原始内容存档于2013-07-08).
- . The Go Programming Language. [2022-11-18]. (原始内容存档于2023-01-03).
- . The Go Programming Language. [2017-11-15]. (原始内容存档于2019-02-13) (英语).
- . stackoverflow.com. [2017-03-20]. (原始内容存档于2020-11-25).
- . [2015-06-09]. (原始内容存档于2018-08-07).
- . [2009-11-12]. (原始内容存档于2013-01-02).
外部链接
- 官方网站
- Golang FAQ(页面存档备份,存于)
- Golang Release History and Support (页面存档备份,存于)
- YouTube上的The Go Programming Language
- IRC:#go-nuts IRC://(irc.freenode.net)
- 邮件列表Archive.is的存盘,存档日期2019-03-14