Go之FAQ(一)

來源:互聯網
上載者:User

標籤:

純粹業餘興趣翻譯,能力有限水平業餘,歡迎拍磚。
文中還有一些句子沒作翻譯,是因為我完全沒弄懂:-)
問題較多, 分part翻譯,本文為第一part。
原文: Frequently Asked Questions (FAQ)

起源What is the purpose of the project?

非系統底層語言的出現已經有十多年的時間, 而在這期間計算環境已經發生了巨大變化。以下是幾大發展趨勢:
- 電腦運算速度有極大提升, 但是軟體開發效率沒有明顯提高。
- 依賴管理是今天軟體開發一個重要部分, 但像C語言中的“header files”阻礙了簡單的依賴分析和快速的編譯。
- 與類似Java, C++等帶有重類型系統的語言相比, 弱類型語言編程的興起促使越來越多的開發人員使用諸如Python或JavaScript這些動態類型語言來進行編程。
- 像記憶體回收和並行計算這些基礎概念在當前流行的系統語言中並沒有得到很好的支援。
- 多核電腦的出現引起了更多的擔憂和疑惑。

我們相信值得去嘗試開發一種支援並發、記憶體回收並且能被快速編譯的新語言。對於以上的幾點:

  • 能夠在一台單機上快速編譯(如幾秒內)GO的一個大項目。
  • Go提供了這樣一個軟體開發模型: 使依賴分析更簡單, 而避免了類似C那樣在檔案和庫上使用依賴的不便。
  • Go的類型系統沒有階層, 所有沒有把時間花在定義類型關係上。同樣, 雖然Go有靜態類型, 它也盡量使類型顯得更加輕量(相對於其他經典Object-Oriented語言來說)。
  • Go提供了完整的記憶體回收機制, 並且在並發執行和通訊方面提供了基礎支援。
  • 基於自身設計, GO在多核機器上的軟體系統的構建給出了方案。

關於這個問題,更詳細和有價值的答案可以參考這篇文章 Go at Google: Language Design in the Service of Software Engineering。

What is the status of the project?

Go在2009/11/10時成為一個開源項目。之後經過幾年的積極發展, 在2012/3/28這天Go1.0穩定版本正式發布。該版本包含了語言規範、標準庫、 常用工具庫, 為建立可靠的企業專案提供了基礎。

有了穩定的基礎, 我們使用Go來開發程式, 項目以及一些工具, 而不是頻繁的換語言或者庫。實際上Go1的目標是提供長期穩定的開發環境。Go 1上的任何更改都是向後相容的。我們要清楚將來的GO應該發展成什麼樣子,而不只是改改版本號碼。

當然, Go會不斷改進, 但方向側重在效能, 可靠性, 可移植性以及一些新功能的開發, 比如完善國際化支援。

將來可能有Go 2版本, 不過目前幾年主要是發展Go 1(譯註: 截止目前, 最新為Go1.6, 於2016-01-27正式發布)。

What’s the origin of the mascot?

吉祥物的logo是由Renée French來設計的, 他同時還設計了Glenda, the Plan 9 bunny。地鼠是從她幾年前穿的WFMU T-shirt獲得靈感而設計的。該logo在Creative Commons Attribution 3.0許可內使用。

What is the history of the project?

Robert Griesemer, Rob Pike和Ken Thompson在2007年9月份變開始在白板上描繪一個新語言的目標。 很快目標便被敲定,而該語言有了最初的輪廓,並且在大家的業餘努力下漸進發展。到了2008年1月份, Ken開始著手設計輸出結果為C語言的編譯器,用以探索思路。到了年中,Go已經成為一個全職項目,並且有充足準備來開發其編譯器。在2008年5月, independently started on a GCC front end for Go using the draft specification(??)。 後半年加入的Russ Cox, 通過原型開始實現Go的語言規則及一些基礎庫。

Go在2009-11-10成員開源項目。社區中的眾多開發人員貢獻了很多建設性建議及討論, 還有代碼。

Why are you creating a new language?

Go之所以誕生, 是對現有語言和系統編程環境不滿的一種驅動釋然。編程變得如此困難, 而語言的選擇也變得迷茫。高效編譯, 高效執行, 易於編程這三者在同一個主流語言中不可同時兼得。開發人員被動選擇了動態類型語言(如Python/JavaScript)以進行安全有效開發,而不是C++或Java。

Go嘗試既做到解析型、動態類型語言那樣易於開發, 也做到靜態、編譯語言一樣高效安全。同樣它側重支援網路及多核編程。
最後, 希望通過Go來加速編譯: 在單台機器上最多需要幾秒鐘時間來完成一個大項目的編譯流程。要達到這些目標,需要解決大量這樣的問題: 一個富於表達而且輕巧的類型系統;並發和記憶體回收等等。現有的庫或者工具並不能很好的解決這些問題, 因此新的語言應運而生。

Go at Google闡述了Go語言誕生的背景以及動機,通過它可以找到更多有關這個問題的答案。

What are Go’s ancestors?

Go很大程度上屬於C家族(基礎文法),參考並吸收了Pascal/Modula/Oberon這些語言的優點(declarations, packages),結合Tony Hoare的CSP理論(如Newsqueak和Limbo)做了一些改進。然而它是一個全新的語言。Go語言設計時都在考慮開發人員可以做什麼以及怎麼做, 至少像我們一樣更加有效率, 也意味著更有樂趣。

What are the guiding principles in the design?

現在的編程包含了太多的記賬, 重複和文檔性工作。
如同Dick Gabriel所說, 閱讀老的程式就像一個善言的研究員和一個善於學習的機器同事之間的一個安靜的對話,而不是和編譯器之間的一場爭吵。但誰會想到詭辯會帶來噪音呢” sophistication(複雜化?)是有原因的—誰也不想回到老的語言—但它是否能更平和的實現呢?

Go嘗試減少輸入的代碼數量。 透過它的設計, 我們嘗試減少混亂和複雜度。在Go中, 沒有前置聲明和標頭檔;所有對象/變數都是只聲明一次。
初始化方式易讀, 自動化而且易用。文法乾淨, 關鍵字輕量。可以使用 := (聲明並定義)的結構來簡化普通運算式: foo.Foo* myFoo = new(foo.Foo)。而最基本的, Go的類型沒有階層, 也就不需要宣告類型之間的關係。這種簡化機制使得Go輕鬆做到富於表達,易於理解。

另外一個重要的原則是保持概念正交。可以實現任何類型的方法;
結構體用來表示資料而介面用來表示抽象;等等. 正交性使得組合操作時更容易清楚其中發生了什麼。

使用Is Google using Go internally?

是的。在Google內部已經有數個Go項目部署在生產環境。一個對外的例子為golang.org網站的後台服務。 它是運行在Google App Engine上生產環境中的一個godoc相關服務。

其他例子像Vitess(用於large-scale SQL installation), dl.google.com(google下載服務, 提供了chrome二進位檔案以及其他一下大體積安裝包)。

Do Go programs link with C/C++ programs?

Go有兩種編譯器, gc和gccgo。gc使用了一種不同的calling convention(Calling Convention是指程式在函數調用時傳遞參數和擷取傳回值所採用的方法:通過寄存器、或通過棧、或者是兩者的混合。)和連結器, 因此只有C程式通過相同的calling convention可以連結;是C編譯器而不是C++編譯器。gccgo作為gcc的前端, 能夠連結到GCC編譯的C/C++程式。

cgo程式提供了一種”外部函數介面”機制,使得在Go代碼中安全調用C庫。
SWIG拓展了C++庫以支援外部調用。

Does Go support Google’s protocol buffers?

有一個獨立的開源項目, 提供了必要的編譯組件和庫。地址:https://github.com/golang/protobuf/

Can I translate the Go home page into another language?

當然。我們鼓勵開發人員用他們的語言去構建Go語言相關網站。
然而如果選擇添加google logo或者brand到你的網站(在golang.org上沒有出現的), 那麼就需要遵守 www.google.com/permissions/guidelines.html上聲明的準則。

設計What’s up with Unicode identifiers?

從ASCII的範圍拓展標識符的空間, 這是很重要的。Go中的rule-indentifier字元必須是用Unicode定義的字母或數字-簡單易懂,易於實現,但是有限制。組合標識符在當前來說是不在設計之內的。Until there is an agreed external definition of what an identifier might be, plus a definition of canonicalization of identifiers that guarantees no ambiguity, it seemed better to keep combining characters out of the mix. Thus we have a simple rule that can be expanded later without breaking programs, one that avoids bugs that would surely arise from a rule that admits ambiguous identifiers.

與此相關,由於一個匯出的identifier必須大寫開頭, 一些由某種或某幾種建立的identifier並不能匯出使用。目前唯一的解決方案是使用類似X日本語的方式, 但這顯然很挫; 我們正在考慮其他的方案。而大小寫與可見度相關(case-for-visibility)的規則不太可能會改, 因為這是Go最常用的一種特性了。

Why does Go not have feature X?

每一種語言都會包含一些新的特性, 而缺少某些人一些最喜愛的特性。Go的設計著重於編碼快樂感, 編譯的速度,正交原則,以及支援一些像並發執行和記憶體回收這樣的特性。你最喜愛的特性可能在Go裡沒有, 可能是因為它並不適合, 也可能是它影響了編譯效能或設計的整潔度, 又或者它使得基本系統模型變得複雜。

如果Go缺失某些特性而影響了你的開發,請原諒我們並研究Go中所包含的特性。你可能會發現一些有趣的彌補方案。

Why does Go not have generic types?

泛型可能會在某個時候加入。我們並不認為這很緊要,雖然我們也知道有些開發人員迫切需要。

泛型提供了便利,但它們會在複雜度上增加類型系統及run-time的成本。
儘管我們一直在思考,但目前還是沒有找到一種設計可以讓價值與複雜度成正比相關。同時, Go中內建map和slice,增強了使用空interface去構建容器的能力(通過顯式拆箱);這意味著很多時候可以這樣編碼已達到使用泛型的效果。

這裡保留一個開放問題,可以從the generics proposal issue擷取更多資訊。

Why does Go not have exceptions?

我們認為將類似try-catch-finaly這樣的異常處理耦合到控制結構中的話,
會產生令人費解的代碼。這也往往鼓勵開發人員去標識過多的一般錯誤,比如開啟檔案失敗。

Go採取了不同的處理方法。對於一般的錯誤處理, Go的多值返回可以在不用返回結果的情況下報告一個錯誤。帶上Go其他特性的一種典型錯誤類型, 可以使得錯誤處理很輕快, 而有別於其他語言。

Go也有一對內建方法,支援發生異常時發送訊號和從異常中恢複。恢複機制僅在方法某部分發生錯誤而狀態異常後執行,這足以處理災難而不需要額外的控制結構。用的好的話可以讓錯誤處理代碼部分更整潔。

更詳細內容請參考Defer, Panic, and Recover

Why does Go not have assertions?

Go不支援斷言。使用斷言不可否認的方便,但我們認為很多人是用了斷言後忽略怎麼正確的處理和報告錯誤。正確的錯誤處理意味著在非致命錯誤發生後程式應該繼續執行而不是崩潰。正確的錯誤報表也意味著錯誤精確發生的位置,儲存了用於分析的錯誤堆棧資訊。精確的錯誤是很有必要的,尤其是開發人員並不熟悉當前的代碼。

我們明白這是爭論的焦點。在Go中, 很多東西和現代實踐理論不同,僅僅是因為我們覺得有必要嘗試不同的實現。

Why build concurrency on the ideas of CSP?

並發和多線程編程是公認的有難度。我們認為這和複雜的設計(如pthreads)分不開, 和過度強調底層細節也有關, 比如mutex, condition變數,memory barrier。使用上層介面可以使代碼更簡單, 即使也有類似鎖這些底層概念。

一個用於並發提供高層次語言支援的最成功的模型來自Hoare的Communicating Sequential Processes, 簡稱CSP模型。 Occam和 Erlang這兩種語言也使用了CSP模型。 Go的並發原型是從該模型的另一個、channel作為第一類對象的部分體系中派生。從早期幾種語言的使用經驗中可以表明, CSP模型可以很好地結合到程式語言架構中使用。

Why goroutines instead of threads?

Goroutine是更容易實現並發編程的一種原因。這個想法已經存在一段時間了,就是在一組thread中多工、獨立執行多個functions。當一個coroutine阻塞時,像調用了阻塞式的系統調用, go運行時會在同一個系統線程上自動將該線程上其他的coroutine移動到另外一個線程上面執行, 因此不會出現阻塞。程式員是看不到這個變化的, 這就是關鍵。結果就是, 調用coroutine會變得很廉價: 他們在棧上只有很小的開銷,通常只佔幾KB記憶體。

為了使棧更小, Go運行時使用了可變的有邊界的棧。一個建立的goroutine擁有幾KB空間, 基本是足夠使用的。Go運行時會自動增加用於儲存棧的空間,從而使得goroutine有足夠可用的記憶體。平均每次函數調用將產生cpu三次微指令的開銷。實踐中在同一個地址空間中同時可以建立上萬個goroutines。如果goroutine就是thread,那更少的數量就能耗光系統資源。

Why are map operations not defined to be atomic?

經過長時間的討論之後, 我們決定map的典型用法不要求在多個goroutine情況下保證安全存取(這些情況是指map為已同步的大資料集或者計算的一部分)。而要求所有map操作加鎖的話, 會減慢程式的速度, 而安全性並沒有明顯提高。這並不是一個容易的決定,因為一個失控的map訪問可能會搞垮整個程式。

The language does not preclude atomic map updates(Go並不排除map的原子更新??).
When required, such as when hosting an untrusted program, the implementation could interlock map access(在需要原子更新時, 如在執行一個不受信任的程式時, 這個實現(原子操作)可以鎖住map的訪問??).

Will you accept my language change?

開發人員經常建議改進該語言-郵件清單裡麵包含了諸如此類內容的曆史-但是很少建議能夠得到採納。

雖然Go是一個開源項目, 它還是受相容性保護的, 這樣可以避免因為更改而破壞現有的項目程式。如果你的建議違反了Go 1.x的規範,我們是不能接受這個想法的, 即使它很優秀。將來的主要release版可能不會相容Go 1.x, 但是我們還不打算討論它未來的樣子。

即使你的建議符合Go 1.x規範,它也不一定符合Go的設計宗旨。參考這裡,Go at Google: Language Design in the Service of Software Engineering闡述了Go的起源和它的設計的背後動機。

類型Is Go an object-oriented language?

Go可以說是,也可以不是OO語言。雖然Go有類型和方法來進行OO編程, 但是沒有類型層次。Go中interface的概念提供了一種截然不同的易用而且在某些方面更通用的方法。也可以將一個類型嵌套到其他類型,以達到相似不盡相同的子類效果。而且,Go中的方法比在C++或Java中更普遍:可以給任何類型的資料定義方法,即使是像integer這樣的內建類型; 而不僅限於結構或類。

同樣由於缺少類型階層, 使得object在Go中比其他諸如C++/Java的語言顯得更加輕便。

How do I get dynamic dispatch of methods?

唯一可以動態調度方法的途徑是通過介面。在struct或者其他具體類型上的方法總是通過靜態解析的。

Why is there no type inheritance?

OO編程, 至少在一些主流語言中, 涉及到太多關於類型關係和關係可以自動派生的這些討論。Go採用了一種不同的方法。

與要求程式員前置聲明兩個類型之間的關係不同, Go中的某個對象只要實現了某介面的所有方法,則該對象就自動實現了該介面。減少了顯式聲明關係的這些負擔,這個方法顯得更加有優勢。物件類型可以同時實現多個介面, 而無需承擔傳統多重繼承的複雜性。interface可以很輕量-介面可以只有一個甚至沒有方法。Interfaces can be added after the fact if a new idea comes along or for testing—without annotating the original types.因為在對象和介面之間並沒有顯式的關係綁定, 也就不需要去管理類型階層。

通過這些idea, 可以構建一些類似型別安全的Unix管道的事情。參考一下,例如fmt.FPrintf如何格式化輸出任何資料, 而不僅僅是一個檔案; 又例如bufio包如何從file I/O中完全獨立出來; 又或者image包如何產生壓縮的圖片檔案。所有這些想法從一個interface(io.Writer, 其實就一個方法Writer)衍生而來。而這還只是表面上的影響。Go的interface對整個程式結構產生了深遠的影響。

這需要一段時間去適應, 而這種類型隱式依賴的風格是Go最有建造力的一個特點。

Why is `len` a function and not a method?

我們也討論過這個問題,最終還是決定將len實現為一個function而不是method, 這樣不會讓基礎類型的介面(在Go意義上)問題複雜化。

Why does Go not support overloading of methods and operators?

如果不需要做類型匹配, 函數調度將很簡單。使用其他語言的經驗告訴我們,能使用多個重名方法而參數或簽名不同時偶爾有用處, 但在實踐中也會讓人迷惑。只通過名字匹配,並且要求類型一致, 在Go系統中是主要的一種簡化決策。

對於運算子多載,似乎是很便利, 但並無必要。沒有它們事情會變的更簡單。

Why doesn’t Go have “implements” declarations?

Go中一種類型要實現一個介面, 只要實現該介面的所有方法就可以了, 無他。這種機制使得介面可以自由定義和使用, 而不必修改現有的代碼。這種類型結構化促進了關注點分離, 而提高了代碼複用,更易構建一種代碼開發模式。介面的語義是Go之所以自稱靈活、輕盈的主要原因之一。

詳情請參考type inheritance

How can I guarantee my type satisfies an interface?

你可以詢問編譯器來驗證類型T是否實現了介面I, 如使用給類型T或類型指標T賦予零值:

type T struct{}var _ I = T{}       // Verify that T implements I.var _ I = (*T)(nil) // Verify that *T implements I.

如果T或T並沒有實現介面I, 在編譯時間便會報錯。

如果你希望interface的使用者顯式聲明實現了某介面, 你可以添加一個名字有此含義的方法到該介面的方法集中。比如:

type Fooer interface {    Foo()    ImplementsFooer()}

然後該類型必須實現Fooer的方法ImplementsFooer,在godoc中註明此處實現。

type Bar struct{}func (b Bar) ImplementsFooer() {}func (b Bar) Foo() {}

大多數的代碼並沒有使用這樣的制約, 因為它有點費解(limit the utility of the interface idea)。然而有時候這樣可以解決由於類似的介面引起混淆的問題。

Why doesn’t type T satisfy the Equal interface?

如下所示,可以通過interface的方法給對象進行比較(同類型不一定同值):

type Equaler interface {    Equal(Equaler) bool}

及類型T:

type T intfunc (t T) Equal(u T) bool { return t == u } // does not satisfy Equaler

與多態系統中的大多數情況不同,T並沒有沒有實現介面Equaler。T.Equal的參數類型是T, 而不是要求的類型Equaler。

在Go中,類型系統沒有自動推導Equal的參數; 這個責任在開發人員身上,可以自己通過定義類型T2來實現介面Equaler:

type T2 intfunc (t T2) Equal(u Equaler) bool { return t == u.(T2) }  // satisfies Equaler

雖然這和其他類型系統不一樣,但Go中任何只要實現了Equaler的類型都可以作為參數傳遞到T2.Equal, 而在運行時需檢查該參數是否為T2類型。一些語言會在編譯期間便保證了這個類型一致。

另一種相關的例子:

type Opener interface {   Open() Reader}func (t T3) Open() *os.File

在Go中, 這個類型T3並沒有實現介面Opener。

在這種情況下, Go類型系統為程式員做的事情的確不多,而缺少子類型的機制使得實現介面的規則變得很簡單: 函數的名字和參數簽名是否和interface中定義的一模一樣?Go的規則也很容易被有效實現。我們覺得這些優點可以彌補Go在自動類型推導上的缺陷。是否在某一天Go應該採用多態類的形式,我們期待有一種方式可以表達這些例子的想法,並且能夠進行靜態檢查。

Go之FAQ(一)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.