Go 語言 前言

2023-02-17 11:24 更新

原文鏈接:https://gopl-zh.github.io/preface.html


Go語言起源

編程語言的演化跟生物物種的演化類似,一個(gè)成功的編程語言的后代一般都會(huì)繼承它們祖先的優(yōu)點(diǎn);當(dāng)然有時(shí)多種語言雜合也可能會(huì)產(chǎn)生令人驚訝的特性;還有一些激進(jìn)的新特性可能并沒有先例。通過觀察這些影響,我們可以學(xué)到為什么一門語言是這樣子的,它已經(jīng)適應(yīng)了怎樣的環(huán)境。

下圖展示了有哪些早期的編程語言對(duì)Go語言的設(shè)計(jì)產(chǎn)生了重要影響。


Go語言有時(shí)候被描述為“類似C語言”,或者是“21世紀(jì)的C語言”。Go從C語言繼承了相似的表達(dá)式語法、控制流結(jié)構(gòu)、基礎(chǔ)數(shù)據(jù)類型、調(diào)用參數(shù)傳值、指針等很多思想,還有C語言一直所看中的編譯后機(jī)器碼的運(yùn)行效率以及和現(xiàn)有操作系統(tǒng)的無縫適配。

但是在Go語言的家族樹中還有其它的祖先。其中一個(gè)有影響力的分支來自Niklaus Wirth所設(shè)計(jì)的?Pascal?語言。然后?Modula-2?語言激發(fā)了包的概念。然后?Oberon?語言摒棄了模塊接口文件和模塊實(shí)現(xiàn)文件之間的區(qū)別。第二代的?Oberon-2?語言直接影響了包的導(dǎo)入和聲明的語法,還有?Oberon?語言的面向?qū)ο筇匦运峁┑姆椒ǖ穆暶髡Z法等。

Go語言的另一支祖先,帶來了Go語言區(qū)別其他語言的重要特性,靈感來自于貝爾實(shí)驗(yàn)室的Tony Hoare于1978年發(fā)表的鮮為外界所知的關(guān)于并發(fā)研究的基礎(chǔ)文獻(xiàn) 順序通信進(jìn)程 ( ?communicating sequential processes?,縮寫為?CSP?。在?CSP?中,程序是一組中間沒有共享狀態(tài)的平行運(yùn)行的處理過程,它們之間使用管道進(jìn)行通信和控制同步。不過 Tony Hoare的?CSP?只是一個(gè)用于描述并發(fā)性基本概念的描述語言,并不是一個(gè)可以編寫可執(zhí)行程序的通用編程語言。

接下來,Rob Pike和其他人開始不斷嘗試將CSP引入實(shí)際的編程語言中。他們第一次嘗試引入CSP特性的編程語言叫 Squeak(老鼠間交流的語言),是一個(gè)提供鼠標(biāo)和鍵盤事件處理的編程語言,它的管道是靜態(tài)創(chuàng)建的。然后是改進(jìn)版的Newsqueak語言,提供了類似C語言語句和表達(dá)式的語法和類似?Pascal?語言的推導(dǎo)語法。?Newsqueak?是一個(gè)帶垃圾回收的純函數(shù)式語言,它再次針對(duì)鍵盤、鼠標(biāo)和窗口事件管理。但是在?Newsqueak?語言中管道是動(dòng)態(tài)創(chuàng)建的,屬于第一類值,可以保存到變量中。

在?Plan9?操作系統(tǒng)中,這些優(yōu)秀的想法被吸收到了一個(gè)叫?Alef?的編程語言中。?Alef?試圖將?Newsqueak?語言改造為系統(tǒng)編程語言,但是因?yàn)槿鄙倮厥諜C(jī)制而導(dǎo)致并發(fā)編程很痛苦。(譯注:在?Alef?之后還有一個(gè)叫?Limbo?的編程語言,Go語言從其中借鑒了很多特性。 具體請(qǐng)參考?Pike?的講稿:http://talks.golang.org/2012/concurrency.slide#9 )

Go語言的其他的一些特性零散地來自于其他一些編程語言;比如?iota?語法是從?APL?語言借鑒,詞法作用域與嵌套函數(shù)來自于?Scheme?語言(和其他很多語言)。當(dāng)然,我們也可以從Go中發(fā)現(xiàn)很多創(chuàng)新的設(shè)計(jì)。比如Go語言的切片為動(dòng)態(tài)數(shù)組提供了有效的隨機(jī)存取的性能,這可能會(huì)讓人聯(lián)想到鏈表的底層的共享機(jī)制。還有Go語言新發(fā)明的?defer?語句。

Go語言項(xiàng)目

所有的編程語言都反映了語言設(shè)計(jì)者對(duì)編程哲學(xué)的反思,通常包括之前的語言所暴露的一些不足地方的改進(jìn)。Go項(xiàng)目是在Google公司維護(hù)超級(jí)復(fù)雜的幾個(gè)軟件系統(tǒng)遇到的一些問題的反思(但是這類問題絕不是Google公司所特有的)。

正如Rob Pike所說,“軟件的復(fù)雜性是乘法級(jí)相關(guān)的”,通過增加一個(gè)部分的復(fù)雜性來修復(fù)問題通常將慢慢地增加其他部分的復(fù)雜性。通過增加功能、選項(xiàng)和配置是修復(fù)問題的最快的途徑,但是這很容易讓人忘記簡潔的內(nèi)涵,即從長遠(yuǎn)來看,簡潔依然是好軟件的關(guān)鍵因素。

簡潔的設(shè)計(jì)需要在工作開始的時(shí)候舍棄不必要的想法,并且在軟件的生命周期內(nèi)嚴(yán)格區(qū)別好的改變和壞的改變。通過足夠的努力,一個(gè)好的改變可以在不破壞原有完整概念的前提下保持自適應(yīng),正如Fred Brooks所說的“概念完整性”;而一個(gè)壞的改變則不能達(dá)到這個(gè)效果,它們僅僅是通過膚淺的和簡單的妥協(xié)來破壞原有設(shè)計(jì)的一致性。只有通過簡潔的設(shè)計(jì),才能讓一個(gè)系統(tǒng)保持穩(wěn)定、安全和持續(xù)的進(jìn)化。

Go項(xiàng)目包括編程語言本身,附帶了相關(guān)的工具和標(biāo)準(zhǔn)庫,最后但并非代表不重要的是,關(guān)于簡潔編程哲學(xué)的宣言。就事后諸葛的角度來看,Go語言的這些地方都做的還不錯(cuò):擁有自動(dòng)垃圾回收、一個(gè)包系統(tǒng)、函數(shù)作為一等公民、詞法作用域、系統(tǒng)調(diào)用接口、只讀的UTF8字符串等。但是Go語言本身只有很少的特性,也不太可能添加太多的特性。例如,它沒有隱式的數(shù)值轉(zhuǎn)換,沒有構(gòu)造函數(shù)和析構(gòu)函數(shù),沒有運(yùn)算符重載,沒有默認(rèn)參數(shù),也沒有繼承,沒有泛型,沒有異常,沒有宏,沒有函數(shù)修飾,更沒有線程局部存儲(chǔ)。但是,語言本身是成熟和穩(wěn)定的,而且承諾保證向后兼容:用之前的Go語言編寫程序可以用新版本的Go語言編譯器和標(biāo)準(zhǔn)庫直接構(gòu)建而不需要修改代碼。

Go語言有足夠的類型系統(tǒng)以避免動(dòng)態(tài)語言中那些粗心的類型錯(cuò)誤,但是,Go語言的類型系統(tǒng)相比傳統(tǒng)的強(qiáng)類型語言又要簡潔很多。雖然,有時(shí)候這會(huì)導(dǎo)致一個(gè)“無類型”的抽象類型概念,但是Go語言程序員并不需要像C++或Haskell程序員那樣糾結(jié)于具體類型的安全屬性。在實(shí)踐中,Go語言簡潔的類型系統(tǒng)給程序員帶來了更多的安全性和更好的運(yùn)行時(shí)性能。

Go語言鼓勵(lì)當(dāng)代計(jì)算機(jī)系統(tǒng)設(shè)計(jì)的原則,特別是局部的重要性。它的內(nèi)置數(shù)據(jù)類型和大多數(shù)的準(zhǔn)庫數(shù)據(jù)結(jié)構(gòu)都經(jīng)過精心設(shè)計(jì)而避免顯式的初始化或隱式的構(gòu)造函數(shù),因?yàn)楹苌俚膬?nèi)存分配和內(nèi)存初始化代碼被隱藏在庫代碼中了。Go語言的聚合類型(結(jié)構(gòu)體和數(shù)組)可以直接操作它們的元素,只需要更少的存儲(chǔ)空間、更少的內(nèi)存寫操作,而且指針操作比其他間接操作的語言也更有效率。由于現(xiàn)代計(jì)算機(jī)是一個(gè)并行的機(jī)器,Go語言提供了基于?CSP?的并發(fā)特性支持。Go語言的動(dòng)態(tài)棧使得輕量級(jí)線程?goroutine?的初始??梢院苄?,因此,創(chuàng)建一個(gè)?goroutine?的代價(jià)很小,創(chuàng)建百萬級(jí)的?goroutine?完全是可行的。

Go語言的標(biāo)準(zhǔn)庫(通常被稱為語言自帶的電池),提供了清晰的構(gòu)建模塊和公共接口,包含I/O操作、文本處理、圖像、密碼學(xué)、網(wǎng)絡(luò)和分布式應(yīng)用程序等,并支持許多標(biāo)準(zhǔn)化的文件格式和編解碼協(xié)議。庫和工具使用了大量的約定來減少額外的配置和解釋,從而最終簡化程序的邏輯,而且,每個(gè)Go程序結(jié)構(gòu)都是如此的相似,因此,Go程序也很容易學(xué)習(xí)。使用Go語言自帶工具構(gòu)建Go語言項(xiàng)目只需要使用文件名和標(biāo)識(shí)符名稱,一個(gè)偶爾的特殊注釋來確定所有的庫、可執(zhí)行文件、測(cè)試、基準(zhǔn)測(cè)試、例子、以及特定于平臺(tái)的變量、項(xiàng)目的文檔等;Go語言源代碼本身就包含了構(gòu)建規(guī)范。

本書的組織

我們假設(shè)你已經(jīng)有一種或多種其他編程語言的使用經(jīng)歷,不管是類似C、C++或Java的編譯型語言,還是類似Python、Ruby、JavaScript的腳本語言,因此我們不會(huì)像對(duì)完全的編程語言初學(xué)者那樣解釋所有的細(xì)節(jié)。因?yàn)?,Go語言的變量、常量、表達(dá)式、控制流和函數(shù)等基本語法也是類似的。

  • 第一章包含了本教程的基本結(jié)構(gòu),通過十幾個(gè)程序介紹了用Go語言如何實(shí)現(xiàn)類似讀寫文件、文本格式化、創(chuàng)建圖像、網(wǎng)絡(luò)客戶端和服務(wù)器通訊等日常工作。
  • 第二章描述了Go語言程序的基本元素結(jié)構(gòu)、變量、新類型定義、包和文件、以及作用域等概念。第三章討論了數(shù)字、布爾值、字符串和常量,并演示了如何顯示和處理Unicode字符。第四章描述了復(fù)合類型,從簡單的數(shù)組、字典、切片到動(dòng)態(tài)列表。第五章涵蓋了函數(shù),并討論了錯(cuò)誤處理、panic和recover,還有defer語句。
  • 第一章到第五章是基礎(chǔ)部分,主流命令式編程語言這部分都類似。個(gè)別之處,Go語言有自己特色的語法和風(fēng)格,但是大多數(shù)程序員能很快適應(yīng)。其余章節(jié)是Go語言特有的:方法、接口、并發(fā)、包、測(cè)試和反射等語言特性。
  • Go語言的面向?qū)ο髾C(jī)制與一般語言不同。它沒有類層次結(jié)構(gòu),甚至可以說沒有類;僅僅通過組合(而不是繼承)簡單的對(duì)象來構(gòu)建復(fù)雜的對(duì)象。方法不僅可以定義在結(jié)構(gòu)體上,而且,可以定義在任何用戶自定義的類型上;并且,具體類型和抽象類型(接口)之間的關(guān)系是隱式的,所以很多類型的設(shè)計(jì)者可能并不知道該類型到底實(shí)現(xiàn)了哪些接口。方法在第六章討論,接口在第七章討論。
  • 第八章討論了基于順序通信進(jìn)程(CSP)概念的并發(fā)編程,使用goroutines和channels處理并發(fā)編程。第九章則討論了傳統(tǒng)的基于共享變量的并發(fā)編程。
  • 第十章描述了包機(jī)制和包的組織結(jié)構(gòu)。這一章還展示了如何有效地利用Go自帶的工具,使用單個(gè)命令完成編譯、測(cè)試、基準(zhǔn)測(cè)試、代碼格式化、文檔以及其他諸多任務(wù)。
  • 第十一章討論了單元測(cè)試,Go語言的工具和標(biāo)準(zhǔn)庫中集成了輕量級(jí)的測(cè)試功能,避免了強(qiáng)大但復(fù)雜的測(cè)試框架。測(cè)試庫提供了一些基本構(gòu)件,必要時(shí)可以用來構(gòu)建復(fù)雜的測(cè)試構(gòu)件。
  • 第十二章討論了反射,一種程序在運(yùn)行期間審視自己的能力。反射是一個(gè)強(qiáng)大的編程工具,不過要謹(jǐn)慎地使用;這一章利用反射機(jī)制實(shí)現(xiàn)一些重要的Go語言庫函數(shù),展示了反射的強(qiáng)大用法。第十三章解釋了底層編程的細(xì)節(jié),在必要時(shí),可以使用unsafe包繞過Go語言安全的類型系統(tǒng)。

每一章都有一些練習(xí)題,你可以用來測(cè)試你對(duì)Go的理解,你也可以探討書中這些例子的擴(kuò)展和替代。

書中所有的代碼都可以從 http://gopl.io 上的Git倉庫下載。?go get?命令根據(jù)每個(gè)例子的導(dǎo)入路徑智能地獲取、構(gòu)建并安裝。只需要選擇一個(gè)目錄作為工作空間,然后將GOPATH環(huán)境變量設(shè)置為該路徑。

必要時(shí),Go語言工具會(huì)創(chuàng)建目錄。例如:

$ export GOPATH=$HOME/gobook    # 選擇工作目錄
$ go get gopl.io/ch1/helloworld # 獲取/編譯/安裝
$ $GOPATH/bin/helloworld        # 運(yùn)行程序
Hello, 世界                     # 這是中文

運(yùn)行這些例子需要安裝Go1.5以上的版本。

$ go version
go version go1.5 linux/amd64

如果使用其他的操作系統(tǒng),請(qǐng)參考 https://golang.org/doc/install 提供的說明安裝。

更多的信息

最佳的幫助信息來自Go語言的官方網(wǎng)站,https://go.dev/ ,它提供了完善的參考文檔,包括編程語言規(guī)范和標(biāo)準(zhǔn)庫等諸多權(quán)威的幫助信息。同時(shí)也包含了如何編寫更地道的Go程序的基本教程,還有各種各樣的在線文本資源和視頻資源,它們是本書最有價(jià)值的補(bǔ)充。Go語言的官方博客 https://go.dev/blog/ 會(huì)不定期發(fā)布一些Go語言最好的實(shí)踐文章,包括當(dāng)前語言的發(fā)展?fàn)顟B(tài)、未來的計(jì)劃、會(huì)議報(bào)告和Go語言相關(guān)的各種會(huì)議的主題等信息(譯注: https://go.dev/talks/ 包含了官方收錄的各種報(bào)告的講稿)。

在線訪問的一個(gè)有價(jià)值的地方是可以從web頁面運(yùn)行Go語言的程序(而紙質(zhì)書則沒有這么便利了)。這個(gè)功能由來自 https://go.dev/play/ 的 ?Go Playground? 提供,并且可以方便地嵌入到其他頁面中,例如 https://go.dev/ 的主頁,或 godoc 提供的文檔頁面中。

?Playground?可以簡單的通過執(zhí)行一個(gè)小程序來測(cè)試對(duì)語法、語義和對(duì)程序庫的理解,類似其他很多語言提供的?REPL?即時(shí)運(yùn)行的工具。同時(shí)它可以生成對(duì)應(yīng)的url,非常適合共享Go語言代碼片段,匯報(bào)bug或提供反饋意見等。

基于 ?Playground ?構(gòu)建的 ?Go Tour?,https://go.dev/tour/welcome/1,是一個(gè)系列的Go語言入門教程,它包含了諸多基本概念和結(jié)構(gòu)相關(guān)的并可在線運(yùn)行的互動(dòng)小程序。

當(dāng)然,?Playground ?和 ?Tour ?也有一些限制,它們只能導(dǎo)入標(biāo)準(zhǔn)庫,而且因?yàn)榘踩脑驅(qū)σ恍┚W(wǎng)絡(luò)庫做了限制。如果要在編譯和運(yùn)行時(shí)需要訪問互聯(lián)網(wǎng),對(duì)于一些更復(fù)雜的實(shí)驗(yàn),你可能需要在自己的電腦上構(gòu)建并運(yùn)行程序。幸運(yùn)的是下載Go語言的過程很簡單,從 https://go.dev/ 下載安裝包應(yīng)該不超過幾分鐘(譯注:感謝偉大的長城,讓大陸的Gopher們都學(xué)會(huì)了自己打洞的基本生活技能,下載時(shí)間可能會(huì)因?yàn)槎吹拇笮〉纫蛩貜膸追昼姷綆滋旎蚋茫缓缶涂梢栽谧约弘娔X上編寫和運(yùn)行Go程序了。

Go語言是一個(gè)開源項(xiàng)目,你可以在 https://pkg.go.dev/std 閱讀標(biāo)準(zhǔn)庫中任意函數(shù)和類型的實(shí)現(xiàn)代碼,和下載安裝包的代碼完全一致。這樣,你可以知道很多函數(shù)是如何工作的, 通過挖掘找出一些答案的細(xì)節(jié),或者僅僅是出于欣賞專業(yè)級(jí)Go代碼。

致謝

Rob PikeRuss Cox,以及很多其他Go團(tuán)隊(duì)的核心成員多次仔細(xì)閱讀了本書的手稿,他們對(duì)本書的組織結(jié)構(gòu)和表述用詞等給出了很多寶貴的建議。在準(zhǔn)備日文版翻譯的時(shí)候,Yoshiki Shibata更是仔細(xì)地審閱了本書的每個(gè)部分,及時(shí)發(fā)現(xiàn)了諸多英文和代碼的錯(cuò)誤。我們非常感謝本書的每一位審閱者,并感謝對(duì)本書給出了重要的建議的Brian Goetz、Corey Kosak、Arnold Robbins、Josh Bleecher Snyder和Peter Weinberger等人。

我們還感謝Sameer Ajmani、Ittai Balaban、David Crawshaw、Billy Donohue、Jonathan Feinberg、Andrew Gerrand、Robert Griesemer、John Linderman、Minux Ma(譯注:中國人,Go團(tuán)隊(duì)成員。)、Bryan Mills、Bala Natarajan、Cosmos Nicolaou、Paul Staniforth、Nigel Tao(譯注:好像是陶哲軒的兄弟)以及Howard Trickey給出的許多有價(jià)值的建議。我們還要感謝David Brailsford和Raph Levien關(guān)于類型設(shè)置的建議。

我們從來自Addison-Wesley的編輯Greg Doench收到了很多幫助,從最開始就得到了越來越多的幫助。來自AW生產(chǎn)團(tuán)隊(duì)的John Fuller、Dayna Isley、Julie Nahil、Chuti Prasertsith到Barbara Wood,感謝你們的熱心幫助。

Alan Donovan特別感謝:Sameer Ajmani、Chris Demetriou、Walt Drummond和Google公司的Reid Tatge允許他有充裕的時(shí)間去寫本書;感謝Stephen Donovan的建議和始終如一的鼓勵(lì),以及他的妻子Leila Kazemi并沒有讓他為了家庭瑣事而分心,并熱情堅(jiān)定地支持這個(gè)項(xiàng)目。

Brian Kernighan特別感謝:朋友和同事對(duì)他的耐心和寬容,讓他慢慢地梳理本書的寫作思路。同時(shí)感謝他的妻子Meg和其他很多朋友對(duì)他寫作事業(yè)的支持。

2015年 10月 于 紐約


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)