Go(又稱Golang)是Google開發的一种静态强类型、編譯型、并发型,并具有垃圾回收功能的编程语言。
羅伯特·格瑞史莫、羅勃·派克及肯·汤普逊於2007年9月开始设计Go,稍後伊恩·蘭斯·泰勒(Ian Lance Taylor)、拉斯·考克斯(Russ Cox)加入專案。Go是基於Inferno作業系統所開發的。Go於2009年11月正式宣布推出,成為開放原始碼專案,支援Linux、macOS、Windows等作業系統。
在2009年与2016年,Go被軟體評價公司TIOBE選為「TIOBE 2016年最佳語言」。
目前,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 沒有這些特色是設計錯誤。
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 字体(一种等宽字体)分别由设计师查爾斯·比格洛和克莉絲·荷姆斯发布。两种字体均采用了WGL4,并且依照着 DIN 1450 标准,可清晰地使用了 large x-height 和 letterforms 。
在2018年8月,原生的图标更换了。待描述完整 然而,Gopher mascot 仍旧命相同的名字。
在2018年8月,Go的主要贡献者发布了两个关于语言新功能的“草稿设计——泛型和异常处理,同时寻求Go用户的反馈。Go 由于在1.x时,缺少对泛型编程的支持和冗长的异常处理而备受批评。
=== 版本历史 ===
Go 1 保證語言規範和標準庫的主要部分相容。直到目前的 Go 1.20 發布,所有版本都履行了這個承諾。
每個主要的 Go 發布版本會受到支援,直到出現兩個新的主要版本為止。
== 代码示例 ==
=== Hello World ===
下面是用Go写成的Hello World程序:
=== HTTP網頁伺服器 ===
透過Go僅需幾行程式碼就完成HTTP網頁伺服器的實現:
=== Echo命令程序 ===
下面的例子说明了怎样用Go去实现一个像Unix中的Echo命令程序:
== 语言特征 ==
=== 撰寫風格 ===
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
三個目录的用途分別為
舉例來說,整個專案目录可能會如下:
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讓其中一個函式同步執行,如此就不需要等待該函式執行完後才能執行下一個函式。
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。
== 參考文獻 ==
== 外部連結 ==