Go语言

<image>

Go（又称Golang）是Google开发的一种静态强类型、编译型、并发型，并具有垃圾回收功能的编程语言。

罗伯特·格瑞史莫、罗勃·派克及肯·汤普逊于2007年9月开始设计Go，稍后伊恩·兰斯·泰勒（Ian Lance Taylor）、拉斯·考克斯（Russ Cox）加入专案。Go于2009年11月正式宣布推出，成为开放源代码专案，支援Linux、macOS、Windows等操作系统。

在2009年与2016年，Go在TIOBE指数中被列选为最佳语言。

目前，Go每半年发布一个二级版本（即从a.x升级到a.y）。

## 描述

Go的语法接近C语言，但对于变量的声明有所不同。Go支持垃圾回收功能。Go的并行计算模型是以东尼·霍尔的通信顺序进程（CSP）为基础，采取类似模型的其他语言包括Occam和Limbo，Go也具有这个模型的特征，比如通道传输。通过goroutine和通道等并行构造可以建造线程池和管道等。在Go 1.8版本中开放插件（Plugin）的支持，这意味着现在能从Go中动态载入部分函式。

与C++相比，Go并不包括如枚举、异常处理、继承、泛型（此功能在Go 1.18版本中加入）、断言、虚函数等功能，但增加了切片（Slice）类型、并发、管道、垃圾回收、接口等特性的语言级支持。对于断言的存在，则持负面态度，同时也为自己不提供型别继承来辩护。

不同于Java，Go原生提供了关联数组（也称为哈希表（Hashes）或字典（Dictionaries））。

## 批评

尽管 Go 的官方与支持者对于语言中不使用泛型与异常处理有着大量的解释说明，但批评声也从未停过。在发表 Go 语言 2.0 的草案时，官方称没有泛型、异常处理与模组对于 Go 发展确实造成了一定的阻碍。

Go 的垃圾回收机制一直被人诟病，直到 1.8 版本垃圾回收的功能才较为稳定。然而尽管如此，Go 的垃圾回收还是远远落后 JVM 的 G1 和 ZGC。Discord 的研发团队在2020年初甚至发表一篇部落格，宣布把其中一个服务从 Go 转移至 Rust，理由是 Go 的垃圾回收会导致每2分钟出现一次卡顿，并且 Discord 研发团队测试了 Go 语言的1.8、1.9、1.10版本这个问题都没有改善。

## 历史

2007年，Google设计Go，目的在于提高在多核、网络机器（networked machines）、大型代码库（codebases）的情况下的开发效率。当时在Google，设计师们想要解决其他语言使用中的缺点，但是仍保留他们的优点。

- 静态类型和运行时效率。（如：C++）
- 可读性和易用性。（如：Python 和 JavaScript）
- 高性能的网络和多进程。

设计师们主要受他们之间流传的“不要像C++”启发。

Go于2009年11月正式宣布推出，版本1.0在2012年3月发布。之后，Go广泛应用于Google的产品以及许多其他组织和开源项目。

在2016年11月，Go（一种无衬线体）和Go Mono 字体（一种等宽字体）分别由设计师查尔斯·比格洛和克莉丝·荷姆斯发布。两种字体均采用了，并且依照着 DIN 1450 标准，可清晰地使用了 large x-height 和 letterforms。

在2018年8月，原生的图标更换了。待描述完整 然而，Gopher mascot 仍旧命相同的名字。

在2018年8月，Go的主要贡献者发布了两个关于语言新功能的“草稿设计——泛型和异常处理，同时寻求Go用户的反馈。Go 由于在1.x时，缺少对泛型编程的支持和冗长的异常处理而备受批评。

### 版本历史

Go 1 保证语言规范和标准库的主要部分相容。直到目前的 Go 1.25 发布，所有版本都履行了这个承诺。

每个主要的 Go 发布版本会受到支援，直到出现两个新的主要版本为止。

Release｜Status｜Release date｜Maintenance end

o｜o｜2012-03-28｜2013-12-01

o｜o｜2013-05-13｜2014-06-18

o｜o｜2013-12-01｜2014-12-10

o｜o｜2014-06-18｜2015-08-19

o｜o｜2014-12-10｜2016-02-17

o｜o｜2015-08-19｜2016-08-15

o｜o｜2016-02-17｜2017-02-16

o｜o｜2016-08-15｜2017-08-24

o｜o｜2017-02-16｜2018-02-16

o｜o｜2017-08-24｜2018-08-24

o｜o｜2018-02-16｜2019-02-25

o｜o｜2018-08-24｜2019-09-03

o｜o｜2019-02-25｜2020-02-25

o｜o｜2019-09-03｜2020-08-11

o｜o｜2020-02-25｜2021-02-16

o｜o｜2020-08-11｜2021-08-16

o｜o｜2021-02-16｜2022-03-15

o｜o｜2021-08-16｜2022-08-02

o｜o｜2022-03-15｜2023-02-01

o｜o｜2022-08-02｜2023-08-08

o｜o｜2023-02-01｜2024-02-06

o｜o｜2023-08-08｜2024-08-13

o｜o｜2024-02-06｜2025-02-11

o｜o｜2024-08-13｜2025-08-12

o｜o｜2025-02-11｜2026-02-04

2025-08-12｜Q3 2026

c｜c｜2026-02-10｜Q1 2027

l

## 代码示例

### Hello World

下面是用Go写成的Hello World程序：

```go
package main

import "fmt"

func main() {
    fmt.Println("Hello, World")
}
```

### HTTP网页服务器

透过Go仅需几行程式码就完成HTTP网页服务器的实现：

```go
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命令程序：

```go
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才开始启用，旧版本请参阅工作区），每个专案都是一个 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`，其目录结构如下：

```
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也非常地适合网络服务。假设有个程式，里面有两个函式：

```go
func main() {
    // 假設 loop 是一個會重複執行十次的迴圈函式。
    // 迴圈執行完畢才會往下執行。
    loop()
    // 執行另一個迴圈。
    loop()
}
```

这个时候透过Go让其中一个函式同步执行，如此就不需要等待该函式执行完后才能执行下一个函式。

```go
func main() {
    // 透過 `go`，我們可以把這個函式同步執行。
    // 如此一來這個函式就不會阻塞主程式的執行。
    go loop()
    // 執行另一個迴圈。
    loop()
}
```

Goroutine是类似线程的概念，属于纤程(区别于协程和线程)。线程属于系统层面，通常来说建立一个新的线程会消耗较多的资源且管理不易；而协程的主要作用是提供在一个线程内的并发性，却不能利用多个处理器线程。而 Goroutine就像轻量级的线程，一个Go程式可以执行超过数万个 Goroutine，并且这些效能都是原生级的，随时都能够关闭、结束，且运行在多个处理器执行绪上。一个核心里面可以有多个Goroutine，透过GOMAXPROCS参数你能够限制Gorotuine可以占用几个系统线程来避免失控。

在内建的官方套件中也不时能够看见Goroutine的应用，像是net/http中用来监听网络服务的函式实际上是建立一个不断执行循环的Goroutine；同时搭配了epoll 等IO多路复用机制维护Goroutine的事件循环。

## 编译器

当前有两个Go编译器分支，分别为官方编译器gc和gccgo。官方编译器在初期使用C写成，后用Go重写从而实现自举。Gccgo是一个使用标准GCC作为后端的Go编译器。

官方编译器支持跨平台编译（但不支持CGO），允许将原始码编译为可在目标系统、架构上执行的二进制文件。

## 应用

由于go的原生跨平台，以及大量的官方库，被用于大量开源程序，例如：docker、Syncthing、ipfs、Hugo、caddy、以太坊、V2Ray、Gitea、TiDB。

## 基本资料

- 日语原文：Go
- 编程范型：编译型，可平行化，结构化，指令式
- 发行时间：2009年11月10日
- 设计者：罗伯特·格瑞史莫、罗勃·派克、肯·汤普逊
- 开发者：Google
- 软件实现：gc (8g，6g，5g)，gccgo
- 许可证：BSD
- 网站：https://go.dev/、https://golang.google.cn/
- 文件扩展名：.go
- 受影响于：C、Oberon、Limbo、Newsqueak
- 操作系统：Linux、macOS、FreeBSD、Windows