Golang 程式設計:為什麼用 (或不用) Golang

【分享本文】
Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Email

    簡介

    Go 語言 (Golang) 是一個靜態型別 (statically-typed) 通用 (general-purpose) 編譯語言 (compiled language),由 Google 公司主導開發。Go 最早於 2009 年問世,對於程式語言來說,算是相當年輕,但 Go 已經吸引許多來自全世界的開發者的目光;Ruby 創造者松本行弘曾說過,一個程式語言生態圈至少要十年才能有成,但 Go 在短短不到十年間於程式語言排名中已名列前矛,像是獲得 TIOBE 2016 年最佳語言等。雖然國內對於 Go 的專書相對少,但國外已經有相當多的學習資料。筆者將於這個系列的文章中介紹 Go 語言。

    Go 語言的核心開發者 Rob Pike 曾撰文介紹 Go 設計的理念,讀者可以到這裡看一看;由該篇文章可知,Go 的誕生,是為了解決實務的工程議題,而非設計出一個在語法機制上很漂亮的語言,所以 Go 語言並不追求語法特性的豐富度,而是以簡約實用為考量。

    Golang 的特性

    Go 語言有以下的特性:

    • 開放原始碼 (open source)
    • 靜態型別的編譯語言;但語法類似於腳本語言 (scripting language)
    • 跨平台 (cross-platform)
    • 內建垃圾回收 (garbage collection),可手動調整觸發時機
    • 內建平行處理 (concurrency) 的語法
    • 內建函式程式設計 (functional programming)
    • 輕量級物件 (lightweight object) 系統
    • 程式風格強制統一
    • 快速編譯
    • 內建開發相關工具
    • 豐富的標準函式庫
    • 成長中的社群資源

    Go 語言本身是開放原始碼的專案,若使用者想了解 Go 如何運作,可以直接觀看 Go 的原始碼;甚至,可以自行修改原始碼,若修改的部分被 Go 核心團隊接受,有機會可以對 Go 本身做出貢獻。而且,Go 本身是以相對友善的 BSD 條款發布,即使是專有 (proprietary) 商業軟體,也可以放心地使用 Go 語言。

    Go 語言是靜態型別編譯語言,對於程式設計者來說,這樣的語言有軟體工程上的優點,像是可以預先進行語法、型別檢查,對於追蹤錯誤更加方便。在相同的演算法下,編譯語言的效能也會比直譯語言佳。比起 C++ 或 Java 等傳統旳編譯語言,Go 的語法相對簡單許多;雖然比起真正的腳本語言,像是 Python 或 Ruby 等,程式碼會稍微長一點,但考量 Go 是編譯語言,這樣的語法已經算是相當簡潔。

    Go 語言的程式碼和標準函式庫是跨平台的,不需要像 C 或 C++ 般利用條件編譯來滿足跨平台的需求;另外,也不需要像 Java 或 C# 般,需要額外的運行環境 (runtime environment),可以直接發布二進位檔 (native executable)。當然,受限於底層的作業系統,不是所有的 Go 程式碼都可以跨平台,像是圖形使用者介面或是繪圖就需要搭配相關的 C 或 C++ 函式庫才能順利運作;Go 標準函式庫和大部分的第三方函式庫的 Go 專案,只要沒有用到 C 或 C++ 的函式庫,大抵上都可以原封不動地移到另一個平台上編譯和使用。

    為了簡化開發流程,Go 採用全自動的垃圾回收;這對 Go 來說是兩面刃,對於高效能或是即時運算的 (real-time) 程式,垃圾回收會阻礙程式的需求。由於這項特性,Go 其實不像其一開始宣稱的,如同 C 或 C++ 的系統程式語言 (system programming language),反而比較像是 Java 或 C# 般的應用程式語言 (application programming language)。

    現在的電腦硬體已經朝向多核心、多處理器、分散式運算等平行化運算的方向發展,但大部分現行的主流語言在發展時沒有將這些因素考慮進去,對於共時性程式多以執行緒 (thread) 為基礎來撰寫,程式碼相對低階,需要處理的細節較多;相對來說,Go 在語法層面即內建對於共時性 (concurrency) 程式的支援,不需要依賴第三方函式庫,使得撰寫共時性程式更加簡單。

    早期 C 和 C++ 在發展時,並沒有一致的工具鏈 (toolchain),像是在 Windows 系統和類 Unix 系統上的工具相差甚大,造成開發跨平台程式的不便。而 Go 在一開始,即內建數個開發工具,包括編譯器 (compiler)、套件管理 (package management)、程式碼重排 (syntax formatting)、語法檢查 (syntax checking) 等,這些工具沒有綁定特定的 IDE 或編輯器 (editor),開發者可自由選用自己喜歡的工作環境。

    只有語言和編譯器本身,無法很快地寫出應用程式,而 Go 還有一套豐富的標準函式庫,可以減少使用者重造輪子,專注在核心功能上;像是 Go 可以在不依賴網頁框架 (web framework) 的情形下,即可使用大部分網頁程式 (web application) 所有的功能;許多 Gophers (Go 程式設計師) 不用任何網頁框架,僅用標準函式庫加上一些第三方套件來撰寫網頁程式。雖然 Go 目前的社群資源不若 Java 或 Python 般豐富,但也有許多開發者投入 Go 套件的開發,使 Go 社群更加茁壯。

    Golang 受批評的特質

    首先,筆者要提醒各位讀者,雖然 Go 語言相當簡潔易學,寫起來近於腳本語言,但 Go 語言並不是完美無缺的。基本上,Go 語言承襲 C 語言的思想,再加上輕量級物件 (lightweight object) 及垃圾回收 (garbage collection)。在這樣的思維下,Go 語言刻意地在語法上保持簡單化、最小化,導致 Go 語言缺乏許多現代語言常見的特性,筆者列出一些實例:

    • 缺乏泛型 (generics)
    • 缺乏函式重載 (function overloading)
    • 缺乏運算子重載 (operator overloading)
    • 缺乏列舉 (enumration)
    • 強制程式碼風格

    要注意的是,缺乏這些特性不會導致我們無法撰寫程式,只是要用其他的手法達成我們的目的,我們會在後續的文章中逐一探討;畢竟,語法特性只是撰寫程式的過程中所用的一些手段,最重要的還是最終的成品。如果我們去比較一些主流語言,可以發現,Go 在思維上比較接近 C,儘量減少花俏的語法魔術,而使用樸實、明確的程式碼風格,讓程式維護者可以很清楚地了解這段程式的目的,而不需要去記憶某些特殊的內隱性語法。

    註:這樣樸實的特性多用 verbose 來形容。

    目前 Go 語言正在籌備 Go 2 的語法的 proposal (提案),未來可能會補足或加入一些新的特性。不過,在 Go 正式跨入下一個大版本前,仍保證會兼容目前已知的語法特性。目前無法確認這些變動會不會像 Python 2 vs. Python 3 一般造成 Go 社群的分裂。從先前其他語言發展的經驗來看,從提案到真正實作仍然要一段不算短的時間,目前學習的 Go 知識仍然是有用的。

    Go 語言的使用情境

    Go 是一門通用型語言,但是,Go 不見得在所有的領域都吃得開,我們會就不同使用情境,分別探討 Go 是否適用。筆者列出一些常見的使用情境:

    • 終端機程式 (console application)
    • 圖形介面程式 (graphic user interface application)
    • 網頁程式 (web application) 和其他伺服器程式 (server application)
    • 行動程式 (mobile application)
    • 電腦遊戲 (computer game)
    • 元件 (component),即其他高階語言的延伸模組 (extension module)

    使用 Go 撰寫終端機程式,可說是相當好的選擇;雖然 Go 的效能不若 C,但 Go 程式碼、標準函式庫、編譯環境都是跨平台的;此外,對於終端機程式來說,效能往往不是最重要的考量;Go 在字串處理也比 C 高階,更加快程式的撰寫。不過,終端機程式不是目前主流的程式類型,通常是程式設計者或專業人士才會使用這種程式:如果有這方面需求,可以考慮用 Go 取代 C 來撰寫程式。

    理論上,搭配良好的圖形使用者函式庫,Go 也有機會成為另一個圖形介面程式語言。不過,這類程式不是 Google 首要考量的目標,目前僅能依賴一些社群套件,像是 GTK+ 或 Qt 的 Go binding 等。除此之外,還有一些有潛力的選項,像是 wxGo 和 ui 專案等。目前來說,由於 Go binding 的 API 較原生 API 落後,用 Go 寫圖形介面程式仍需審慎評估,至少要瀏覽一下該套件的 API,以了解是否能夠符合自己的需求,以免跳下去後才發現不符自己的期望。

    Google 是以網路和網頁程式起家,可想而知,網頁程式和其他伺服器程式可說是 Go 的強項,也最符合 Google 本身的利益。觀察一下 Go 標準函式庫即可發現 Go 對伺服器程式的支援相當地完善,除此之外也有許多社群套件,目前已有一些商業公司將 Go 用於網頁程式和伺服器程式。這類應該應該是目前 Go 最適合的開發項目 (sweet spot)。

    雖然 Go 專案裡有一項和行動軟體相關的專案,但是,這項專案一直保持在實驗性質 (experimental)。另外,由於 Google 和 Oracle 間因 Java 而產生的訴訟,Google 對 Android 需要採取一定的策略,除了繼續使用 Java 外,採用 Kotlin (一個新興 Java 平台語言) 做為另一個開發 Android 程式的新選擇,或是使用 Dart 加上 Flutter 這個新的平台;如果在加上 Go mobile,我們就有四個開發 Android 程式的方案。說實在的,過多重覆的選擇反而造成社群資源分散,Google 也需要不同團隊去維護這些資源。現階段來說,使用 Go 不是行動軟體的最佳選擇。

    由於 Go 的特性,Go 不太適合即時運算程式,目前以 Go 撰寫的電腦遊戲也沒有很多。雖然有一些以 Go 撰寫的遊戲引擎 (game engine),像是 Ebiten (2D)、Azul3D (3D) 等,但這些遊戲引擎畢竟不是市場主流,如果某一天這些引擎未繼續開發,自己的專案就形同斷頭了。如果遊戲是要營利,應該要用更主流的開發工具;反之,如果不以營利為考量,利用這些引擎撰寫小型電腦遊戲其實也不失為學習程式設計的好方法。

    Go 在 1.5 版加入了輸出 C 函式庫的功能;理論上,透過這個功能,我們可以用 Go 代替 C (或 C++),為其他高階語言,像是 Python 或 Ruby 等,撰寫延伸模組;然而,經筆者實測,發現問題多多:最重要的議題在於 Go 程式無法輸出結構 (struct),使得我們幾乎無法撰寫實用的 C 函式庫;替代的方式是在函式間傳遞 JSON 或 XML 等字串,但這等於每次函式呼叫都要進行字串解析,往往使得效能低下。目前 Go 社群對這個議題的討論度不高,看來這不是 Go 主要的發展目標。

    結語

    經過本文的介紹,讀者應該對於 Go 的特性及使用情境有更多了解,對於是否要在自己的下一個專案中使用 Go 更有信心。在下一篇文章中,我們會介紹如何安裝 Go,以做為開發 Go 程式的準備。

    【分享本文】
    Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Email
    【追蹤新文章】
    Facebook Twitter Plurk