Go

(又稱[4])是Google開發的一种静态强类型編譯型,并具有垃圾回收功能的编程语言

Go
編譯型結構化指令式
設計者羅伯特·格瑞史莫
羅勃·派克
肯·汤普逊
實作者Google
2009年11月10日2009-11-10
当前版本
  • 1.22.2 (2024年4月3日;穩定版本)[1]
操作系统LinuxmacOSFreeBSDWindows
許可證BSD
文件扩展名.go
網站https://go.dev/
https://golang.google.cn/[2]
主要實作產品
gc (8g,6g,5g),gccgo
啟發語言
COberonLimboNewsqueak[3]
Gopher(囊鼠科),Go的吉祥物

羅伯特·格瑞史莫羅勃·派克肯·汤普逊於2007年9月开始设计Go,[3]稍後伊恩·蘭斯·泰勒()、拉斯·考克斯()加入專案。Go是基於Inferno作業系統所開發的。[5]Go於2009年11月正式宣布推出,成為開放原始碼專案,支援LinuxmacOSWindows等作業系統。[6]

在2016年,Go被軟體評價公司TIOBE選為「TIOBE 2016年最佳語言」。[7]

目前,Go每半年发布一个二级版本(即从升级到)。

描述

Go的语法接近C语言,但对于变量的声明有所不同。Go支持垃圾回收功能。Go的并行计算模型是以東尼·霍爾通信顺序进程(CSP)为基础,采取类似模型的其他语言包括OccamLimbo[3],Go也具有这个模型的特征,比如通道传输。通过goroutine和通道等并行构造可以建造线程池管道[8]。在1.8版本中開放插件(Plugin)的支持,這意味著現在能從Go中動態載入部分函式。

与C++相比,Go並不包括如枚举异常处理继承泛型(此功能在go1.18中加入)、断言虚函数等功能,但增加了切片(Slice) 型、并发、管道、垃圾回收接口等特性的语言级支持[3]。對於断言的存在,則持負面態度,同時也為自己不提供型別继承來辯護。

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

批評

儘管 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有定義如下的撰寫風格:

  1. 每行程式結束後不需要撰寫分號;
  2. 大括號{不能夠換行放置。
  3. if判斷式和for迴圈不需要以小括號包覆起來。
  4. 使用 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),允许将原始码编译为可在目标系统、架构上执行的二进制文件。

应用

由于go的原生跨平台,以及大量的官方库,被用于大量开源程序,例如:dockerSyncthingipfsHugocaddy以太坊V2RayGiteaTiDB

參考文獻

  1. .
  2. . [2020-09-14]. (原始内容存档于2021-08-14).
  3. . [2009-11-12]. (原始内容存档于2013-01-02).
  4. . [2018-05-07]. (原始内容存档于2020-11-28).
  5. . [2009-11-20]. (原始内容存档于2010-08-02).
  6. . [2009-11-12]. (原始内容存档于2012-03-20).
  7. . [2018-09-17]. (原始内容存档于2018-09-17).
  8. . golang.org. [2020-05-07]. (原始内容存档于2021-02-05).
  9. . [2021-03-15]. (原始内容存档于2021-01-26).
  10. . [2021-03-15]. (原始内容存档于2022-05-11).
  11. . [2018-10-08]. (原始内容存档于2021-01-25).
  12. Pike, Rob. . Stanford EE Computer Systems Colloquium. Stanford University. 2010-04-28 [2020-01-14]. (原始内容存档于2014-06-12). Video available 页面存档备份,存于.
  13. . golang.org. [2016-02-26]. (原始内容存档于2017-02-25).
  14. Andrew Binstock. . 2011-05-18 [2014-02-07]. (原始内容存档于2014-03-13).
  15. Pike, Rob. . 2012 [2020-01-14]. (原始内容存档于2016-03-21).
  16. Robert Griesemer. . 2015 [2020-01-14]. (原始内容存档于2017-01-16).
  17. Griesemer, Robert; Pike, Rob; Thompson, Ken; Taylor, Ian; Cox, Russ; Kim, Jini; Langley, Adam. . Google Open Source. Google. [2018-05-17]. (原始内容存档于2021-01-26).
  18. 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++.
  19. . [2014-12-11]. (原始内容存档于2017-02-17).
  20. . [2013-03-09]. (原始内容存档于2017-02-25).
  21. . Go. 2016-11-16 [2019-03-12]. (原始内容存档于2019-07-31).
  22. . GitHub. Google. [2019-04-02]. (原始内容存档于2019-07-31).
  23. . blog.golang.org. [2018-11-09]. (原始内容存档于2020-11-25).
  24. . [2018-09-12]. (原始内容存档于2021-01-26).
  25. . 2018-08-28 [2020-01-14]. (原始内容存档于2021-01-31).
  26. . golang.org. [2023-04-12]. (原始内容存档于2017-10-02).
  27. . go.dev. [2023-04-12]. (原始内容存档于2023-05-30).
  28. . golang.org. [2023-04-12]. (原始内容存档于2017-02-17).
  29. . [2009-11-20]. (原始内容存档于2013-07-08).
  30. . The Go Programming Language. [2022-11-18]. (原始内容存档于2023-01-03).
  31. . The Go Programming Language. [2017-11-15]. (原始内容存档于2019-02-13) (英语).
  32. . stackoverflow.com. [2017-03-20]. (原始内容存档于2020-11-25).
  33. . [2015-06-09]. (原始内容存档于2018-08-07).
  34. . [2009-11-12]. (原始内容存档于2013-01-02).

外部連結

This article is issued from Wikipedia. The text is licensed under Creative Commons - Attribution - Sharealike. Additional terms may apply for the media files.