golang语言-1-go普及知识
Go 語言的官方網站是 golang.org,這個站點采用 Python 作為前端,并且使用 Go 語言自帶的工具 godoc 運行在 Google App Engine 上來作為 Web 服務器提供文本內容。在官網的首頁有一個功能叫做 Go Playground,是一個 Go 代碼的簡單編輯器的沙盒,它可以在沒有安裝 Go 語言的情況下在你的瀏覽器中編譯并運行 Go,它提供了一些示例,其中包括國際慣例 “Hello, World!”。
更多的信息詳見 github.com/golang/go,Go 項目 Bug 追蹤和功能預期詳見github.com/golang/go/issues。
谷歌郵件列表 golang-nuts 非常活躍,每天的討論和問題解答數以百計。
關于 Go 語言在 Google App Engine 的應用,這里有一個單獨的郵件列表 google-appengine-go,不過 2 個郵件列表的討論內容并不是分得很清楚,都會涉及到相關的話題。go-lang.cat-v.org/ 是 Go 語言開發社區的資源站,irc.freenode.net 的#go-nuts 是官方的 Go IRC 頻道。
@golang 是 Go 語言在 Twitter 的官方帳號,大家一般使用 #golang 作為話題標簽。
這里還有一個在 Linked-in 的小組:www.linkedin.com/groups?gid=2524765&trk=myg_ugrp_ovr。
Go 編程語言的維基百科:en.wikipedia.org/wiki/Go_(programming_language)
Go 語言相關資源的搜索引擎頁面:gowalker.org
Go 語言還有一個運行在 Google App Engine 上的 Go Tour,你也可以通過執行命令 go install go-tour.googlecode.com/hg/gotour 安裝到你的本地機器上。對于中文讀者,可以訪問該指南的中文版本,或通過命令go install https://bitbucket.org/mikespook/go-tour-zh/gotour 進行安裝。
Go 語言并不是憑空而造的,而是和 C++、Java 和 C# 一樣屬于 C 系。不僅如此,設計者們還汲取了其它編程語言的精粹部分融入到 Go 語言當中。
在聲明和包的設計方面,Go 語言受到 Pascal、Modula 和 Oberon 系語言的影響;在并發原理的設計上,Go 語言從同樣受到 Tony Hoare 的 CSP(通信序列進程Communicating Squential Processes)理論影響的 Limbo 和 Newsqueak 的實踐中借鑒了一些經驗,并使用了和 Erlang 類似的機制。
這是一門完全開源的編程語言,因為它使用 BSD 授權許可,所以任何人都可以進行商業軟件的開發而不需要支付任何費用。
盡管為了能夠讓目前主流的開發者們能夠對 Go 語言中的類 C 語言的語法感到非常親切而易于轉型,但是它在極大程度上簡化了這些語法,使得它們比 C/C++ 的語法更加簡潔和干凈。同時,Go 語言也擁有一些動態語言的特性,這使得使用 Python 和 Ruby 的開發者們在使用 Go 語言的時候感覺非常容易上手。
Go 語言的主要目標是將靜態語言的安全性和高效性與動態語言的易開發性進行有機結合,達到完美平衡,從而使編程變得更加有樂趣,而不是在艱難抉擇中痛苦前行。
因此,Go 語言是一門類型安全和內存安全的編程語言。雖然 Go 語言中仍有指針的存在,但并不允許進行指針運算。
Go 語言的另一個目標是對于網絡通信、并發和并行編程的極佳支持,從而更好地利用大量的分布式和多核的計算機,這一點對于谷歌內部的使用來說就非常重要了。設計者通過 goroutine 這種輕量級線程的概念來實現這個目標,然后通過 channel 來實現各個 goroutine 之間的通信。他們實現了分段棧增長和 goroutine 在線程基礎上多路復用技術的自動化。
Go 語言中另一個非常重要的特性就是它的構建速度(編譯和鏈接到機器代碼的速度),一般情況下構建一個程序的時間只需要數百毫秒到幾秒。整個 Go 語言標準庫的編譯時間一般都在 20 秒以內,其它的常規項目也只需要半秒鐘的時間來完成編譯工作。
Go 語言還能夠在運行時進行反射相關的操作。
使用 go install 能夠很輕松地對第三方包進行部署。
Go 語言有一套完整的編碼規范,你可以在 Go 語言編碼規范 頁面進行查看。
它不像 Ruby 那樣通過實現過程來定義編碼規范。作為一門具有明確編碼規范的語言,它要求可以采用不同的編譯器如 gc 和 gccgo(第 2.1 節)進行編譯工作,這對語言本身擁有更好的編碼規范起到很大幫助。
LALR 是 Go 語言的語法標準,你也可以在src/cmd/internal/gc/go.y 中查看到,這種語法標準在編譯時不需要符號表來協助解析。
Go 語言從本質上(程序和結構方面)來實現并發編程。
因為 Go 語言沒有類和繼承的概念,所以它和 Java 或 C++ 看起來并不相同。但是它通過接口(interface)的概念來實現多態性。Go 語言有一個清晰易懂的輕量級類型系統,在類型之間也沒有層級之說。因此可以說這是一門混合型的語言。
Go 語言使用靜態類型,所以它是類型安全的一門語言,加上通過構建到本地代碼,程序的執行速度也非常快。
作為強類型語言,隱式的類型轉換是不被允許的,記住一條原則:讓所有的東西都是顯式的。
Go 語言其實也有一些動態語言的特性(通過關鍵字 var),所以它對那些逃離 Java 和 .Net 世界而使用 Python、Ruby、PHP 和 JavaScript 的開發者們也具有很大的吸引力。
Go 語言支持交叉編譯,比如說你可以在運行 Linux 系統的計算機上開發運行下 Windows 下運行的應用程序。這是第一門完全支持 UTF-8 的編程語言,這不僅體現在它可以處理使用 UTF-8 編碼的字符串,就連它的源碼文件格式都是使用的 UTF-8 編碼。Go 語言做到了真正的國際化!
Go 語言被設計成一門應用于搭載 Web 服務器,存儲集群或類似用途的巨型中央服務器的系統編程語言。對于高性能分布式系統領域而言,Go 語言無疑比大多數其它語言有著更高的開發效率。它提供了海量并行的支持,這對于游戲服務端的開發而言是再好不過了。
Go 語言一個非常好的目標就是實現所謂的復雜事件處理(CEP),這項技術要求海量并行支持,高度的抽象化和高性能。當我們進入到物聯網時代,CEP 必然會成為人們關注的焦點。
但是 Go 語言同時也是一門可以用于實現一般目標的語言,例如對于文本的處理,前端展現,甚至像使用腳本一樣使用它。
值得注意的是,因為垃圾回收和自動內存分配的原因,Go 語言不適合用來開發對實時性要求很高的軟件。
面向對象語言中使用的特性 Go 語言都沒有支持,但其中的一部分可能會在未來被支持。- 為了簡化設計,不支持函數重載和操作符重載
- 為了避免在 C/C++ 開發中的一些 Bug 和混亂,不支持隱式轉換
- Go 語言通過另一種途徑實現面向對象設計來放棄類和類型的繼承
- 盡管在接口的使用方面可以實現類似變體類型的功能,但本身不支持變體類型
- 不支持動態加載代碼
- 不支持動態鏈接庫
- 不支持泛型
- 通過 recover 和 panic 來替代異常機制
- 不支持斷言
- 不支持靜態變量
關于 Go 語言開發團隊對于這些方面的討論,你可以通過 Go 常見問題 頁面查看。
列舉一些 Go 語言的必殺技:- 簡化問題,易于學習
- 內存管理,簡潔語法,易于使用
- 快速編譯,高效開發
- 高效執行
- 并發支持,輕松駕馭
- 靜態類型
- 標準類庫,規范統一
- 易于部署
- 文檔全面
- 免費開源
Go 語言開發團隊開發了適用于以下操作系統的編譯器:
- Linux
- FreeBSD
- Mac OS X(也稱為 Darwin)
目前有2個版本的編譯器:Go 原生編譯器 gc 和非原生編譯器 gccgo,這兩款編譯器都是在類 Unix 系統下工作 。其中,gc 版本的編譯器已經被移植到 Windows 平臺上,并集成在主要發行版中,你也可以通過安裝 MinGW 從而在 Windows 平臺下使用 gcc 編譯器。這兩個編譯器都是以單通道的形式工作。
你可以獲取以下平臺上的 Go 1.4 源碼和二進制文件:
- Linux 2.6+:amd64、386 和 arm 架構
- Mac OS X(Snow Leopard + Lion):amd64 和 386 架構
- Windows 2000+:amd64 和 386 架構
對于非常底層的純 Go 語言代碼或者包而言,在各個操作系統平臺上的可移植性是非常強的,只需要將源碼拷貝到相應平臺上進行編譯即可,或者可以使用交叉編譯來構建目標平臺的應用程序。但如果你打算使用 cgo 或者類似文件監控系統的軟件,就需要根據實際情況進行相應地修改了。
Go 原生編譯器 gc:
主要基于 Ken Thompson 先前在 Plan 9 操作系統上使用的 C 工具鏈。
Go 語言的編譯器和鏈接器都是使用 C 語言編寫并產生本地代碼,Go 不存在自我引導之類的功能。因此如果使用一個有不同指令集的編譯器來構建 Go 程序,就需要針對操作系統和處理器架構(32 位操作系統或 64 位操作系統)進行區別對待。
這款編譯器使用非分代、無壓縮和并行的方式進行編譯,它的編譯速度要比 gccgo 更快,產生更好的本地代碼,但編譯后的程序不能夠使用 gcc 進行鏈接。
編譯器目前支持以下基于 Intel 或 AMD 處理器架構的程序構建。
圖2.1 gc 編譯器支持的處理器架構
當你第一次看到這套命名系統的時候你會覺得很奇葩,不過這些命名都是來自于 Plan 9 項目。
g = 編譯器:將源代碼編譯為項目代碼(程序文本)l = 鏈接器:將項目代碼鏈接到可執行的二進制文件(機器代碼)(相關的 C 編譯器名稱為 6c、8c 和 5c,相關的匯編器名稱為 6a、8a 和 5a)
標記(Flags) 是指可以通過命令行設置可選參數來影響編譯器或鏈接器的構建過程或得到一個特殊的目標結果。
可用的編譯器標記如下:
flags:-I 針對包的目錄搜索-d 打印聲明信息-e 不限制錯誤打印的個數-f 打印棧結構-h 發生錯誤時進入恐慌(panic)狀態-o 指定輸出文件名 // 詳見第3.4節-S 打印產生的匯編代碼-V 打印編譯器版本 // 詳見第2.3節-u 禁止使用 unsafe 包中的代碼-w 打印歸類后的語法解析樹-x 打印 lex tokens從 Go 1.0.3 版本開始,不再使用 8g,8l 之類的指令進行程序的構建,取而代之的是統一的 go build 和 go install 等命令,而這些指令會自動調用相關的編譯器或鏈接器。
如果你想獲得更深層次的信息,你可以在目錄 $GOROOT/src/cmd 下找到編譯器和鏈接器的源代碼。Go 語言本身是由 C 語言開發的,而不是 Go 語言(Go 1.5 開始自舉)。詞法分析程序是 GNU bison,語法分析程序是名為$GOROOT/src/cmd/gc/go.y 的 yacc 文件,它會在同一目錄輸出 y.tab.{c,h} 文件。如果你想知道更多有關構建過程的信息,你可以在$GOROOT/src/make.bash 中找到。
大部分的目錄都包含了名為 doc.go 的文件,這個文件提供了更多詳細的信息。
gccgo 編譯器:
一款相對于 gc 而言更加傳統的編譯器,使用 GCC 作為后端。GCC 是一款非常流行的 GNU 編譯器,它能夠構建基于眾多處理器架構的應用程序。編譯速度相對 gc 較慢,但產生的本地代碼運行要稍微快一點。它同時也提供一些與 C 語言之間的互操作性。
從 Go 1 版本開始,gc 和 gccgo 在編譯方面都有等價的功能。
文件擴展名與包(package):
Go 語言源文件的擴展名很顯然就是 .go。
C 文件使用后綴名 .c,匯編文件使用后綴名 .s。所有的源代碼文件都是通過包(packages)來組織。包含可執行代碼的包文件在被壓縮后使用擴展名.a(AR 文檔)。
Go 語言的標準庫(第 9.1 節)包文件在被安裝后就是使用這種格式的文件。
注意 當你在創建目錄時,文件夾名稱永遠不應該包含空格,而應該使用下劃線 "_" 或者其它一般符號代替。
環境變量
Go 開發環境依賴于一些操作系統環境變量,你最好在安裝 Go 之間就已經設置好他們。如果你使用的是 Windows 的話,你完全不用進行手動設置,Go 將被默認安裝在目錄c:/go 下。這里列舉幾個最為重要的環境變量:
- $GOROOT 表示 Go 在你的電腦上的安裝位置,它的值一般都是 $HOME/go,當然,你也可以安裝在別的地方。
- $GOARCH 表示目標機器的處理器架構,它的值可以是 386、amd64 或 arm。
- $GOOS 表示目標機器的操作系統,它的值可以是 darwin、freebsd、linux 或 windows。
- $GOBIN 表示編譯器和鏈接器的安裝位置,默認是 $GOROOT/bin,如果你使用的是 Go 1.0.3 及以后的版本,一般情況下你可以將它的值設置為空,Go 將會使用前面提到的默認值。
目標機器是指你打算運行你的 Go 應用程序的機器。
Go 編譯器支持交叉編譯,也就是說你可以在一臺機器上構建運行在具有不同操作系統和處理器架構上運行的應用程序,也就是說編寫源代碼的機器可以和目標機器有完全不同的特性(操作系統與處理器架構)。
為了區分本地機器和目標機器,你可以使用 $GOHOSTOS 和 $GOHOSTARCH 設置目標機器的參數,這兩個變量只有在進行交叉編譯的時候才會用到,如果你不進行顯示設置,他們的值會和本地機器($GOOS 和$GOARCH)一樣。
- $GOPATH 默認采用和 $GOROOT 一樣的值,但從 Go 1.1 版本開始,你必須修改為其它路徑。它可以包含多個包含 Go 語言源碼文件、包文件和可執行文件的路徑,而這些路徑下又必須分別包含三個規定的目錄:src、pkg 和bin,這三個目錄分別用于存放源碼文件、包文件和可執行文件。
- $GOARM 專門針對基于 arm 架構的處理器,它的值可以是 5 或 6,默認為 6。
- $GOMAXPROCS 用于設置應用程序可使用的處理器個數與核數,
在接下來的章節中,我們將會討論如何在 Linux、Mac OS X 和 Windows 上安裝 Go 語言。在 FreeBSD 上的安裝和 Linux 非常類似。開發團隊正在嘗試將 Go 語言移植到其它例如 OpenBSD、DragonFlyBSD、NetBSD、Plan 9、Haiku 和 Solaris 操作系統上,你可以在這個頁面找到最近的動態:Go Porting Efforts。
在 Linux 上安裝 Go
如果你能夠自己下載并編譯 Go 的源代碼來說是非常有教育意義的,你可以根據這個頁面找到安裝指南和下載地址:Download the Go distribution。
我們接下來也會帶你一步步的完成安裝過程。
設置 Go 環境變量
我們在 Linux 系統下一般通過文件 $HOME/.bashrc 配置自定義環境變量,根據不同的發行版也可能是文件 $HOME/.profile,然后使用 gedit 或 vi 來編輯文件內容。
export GOROOT=$HOME/go為了確保相關文件在文件系統的任何地方都能被調用,你還需要添加以下內容:
export PATH=$PATH:$GOROOT/bin在開發 Go 項目時,你還需要一個環境變量來保存你的工作目錄。
export GOPATH=$HOME/Applications/Go$GOPATH 可以包含多個工作目錄,取決于你的個人情況。如果你設置了多個工作目錄,那么當你在之后使用 go get(遠程包安裝命令)時遠程包將會被安裝在第一個目錄下。
在完成這些設置后,你需要在終端輸入指令 source .bashrc 以使這些環境變量生效。然后重啟終端,輸入 go env 和env 來檢查環境變量是否設置正確。
安裝 C 工具
Go 的工具鏈是用 C 語言編寫的,因此在安裝 Go 之前你需要先安裝相關的 C 工具。如果你使用的是 Ubuntu 的話,你可以在終端輸入以下指令( 譯者注:由于網絡環境的特殊性,你可能需要將每個工具分開安裝 )。
sudo apt-get install bison ed gawk gcc libc6-dev make你可以在其它發行版上使用 RPM 之類的工具。
獲取 Go 源代碼
從 官方頁面 或 國內鏡像 下載 Go 的源碼包到你的計算機上,然后將解壓后的目錄 go 通過命令移動到 $GOROOT 所指向的位置。
wget https://storage.googleapis.com/golang/go<VERSION>.src.tar.gztar -zxvf go<VERSION>.src.tar.gzsudo mv go $GOROOT構建 Go
在終端使用以下指令來進行編譯工作。
cd $GOROOT/src./all.bash在完成編譯之后(通常在 1 分鐘以內,如果你在 B 型樹莓派上編譯,一般需要 1 個小時),你會在終端看到如下信息被打印:
圖 2.3 完成編譯后在終端打印的信息
注意事項
在測試 net/http 包時有一個測試會嘗試連接 google.com,你可能會看到如下所示的一個無厘頭的錯誤報告:
‘make[2]: Leaving directory `/localusr/go/src/pkg/net’如果你正在使用一個帶有防火墻的機器,我建議你可以在編譯過程中暫時關閉防火墻,以避免不必要的錯誤。
解決這個問題的另一個辦法是通過設置環境變量 $DISABLE_NET_TESTS 來告訴構建工具忽略 net/http 包的相關測試:
export DISABLE_NET_TESTS=1如果你完全不想運行包的測試,你可以直接運行 ./make.bash 來進行單純的構建過程。
測試安裝
使用你最喜愛的編輯器來輸入以下內容,并保存為文件名 test.go。
示例 2.1 hello_world1.go
package mainfunc main() {println("Hello", "world") }切換相關目錄到下,然后執行指令 go run hello_world1.go,將會打印信息:Hello, world。
驗證安裝版本
你可以通過在終端輸入指令 go version 來打印 Go 的版本信息。
如果你想要通過 Go 代碼在運行時檢測版本,可以通過以下例子實現。
示例 2.2 version.go
package mainimport ("fmt""runtime" )func main() {fmt.Printf("%s", runtime.Version()) }這段代碼將會輸出 go1.4.2 或類似字符串。
更新版本
你可以在 發布歷史 頁面查看到最新的穩定版。
當前最新的穩定版 Go 1 系列于 2012 年 3 月 28 日發布。
Go 的源代碼有以下三個分支:
- Go release:最新穩定版,實際開發最佳選擇- Go weekly:包含最近更新的版本,一般每周更新一次- Go tip:永遠保持最新的版本,相當于內測版當你在使用不同的版本時,注意官方博客發布的信息,因為你所查閱的文檔可能和你正在使用的版本不相符。
安裝目錄清單
你的 Go 安裝目錄($GOROOT)的文件夾結構應該如下所示:
README.md, AUTHORS, CONTRIBUTORS, LICENSE
- /bin:包含可執行文件,如:編譯器,Go 工具
- /doc:包含示例程序,代碼工具,本地文檔等
- /lib:包含文檔模版
- /misc:包含與支持 Go 編輯器有關的配置文件以及 cgo 的示例
- /os_arch:包含標準庫的包的對象文件(.a)
- /src:包含源代碼構建腳本和標準庫的包的完整源代碼(Go 是一門開源語言)
- /src/cmd:包含 Go 和 C 的編譯器和命令行腳本
Go 運行時(runtime)
盡管 Go 編譯器產生的是本地可執行代碼,這些代碼仍舊運行在 Go 的 runtime(這部分的代碼可以在 runtime 包中找到)當中。這個 runtime 類似 Java 和 .NET 語言所用到的虛擬機,它負責管理包括內存分配、垃圾回收、棧處理、goroutine、channel、切片(slice)、map 和反射(reflection)等等。
runtime 主要由 C 語言編寫(Go 1.5 開始自舉),并且是每個 Go 包的最頂級包。你可以在目錄 $GOROOT/src/runtime 中找到相關內容。
垃圾回收器 Go 擁有簡單卻高效的標記-清除回收器。它的主要思想來源于 IBM 的可復用垃圾回收器,旨在打造一個高效、低延遲的并發回收器。目前 gccgo 還沒有回收器,同時適用 gc 和 gccgo 的新回收器正在研發中。使用一門具有垃圾回收功能的編程語言不代表你可以避免內存分配所帶來的問題,分配和回收內容都是消耗 CPU 資源的一種行為。
Go 的可執行文件都比相對應的源代碼文件要大很多,這恰恰說明了 Go 的 runtime 嵌入到了每一個可執行文件當中。當然,在部署到數量巨大的集群時,較大的文件體積也是比較頭疼的問題。但總得來說,Go 的部署工作還是要比 Java 和 Python 輕松得多。因為 Go 不需要依賴任何其它文件,它只需要一個單獨的靜態文件,這樣你也不會像使用其它語言一樣在各種不同版本的依賴文件之間混淆。
Go 解釋器
因為 Go 具有像動態語言那樣快速編譯的能力,自然而然地就有人會問 Go 語言能否在 REPL(read-eval-print loop)編程環境下實現。Sebastien Binet 已經使用這種環境實現了一個 Go 解釋器,你可以在這個頁面找到:https://github.com/sbinet/igo。
編輯器和集成開發環境
這些編輯器包含了代碼高亮和其它與 Go 有關的一些使用工具:Emacs、Vim、Xcode 6、KD Kate、TextWrangler、BBEdit、McEdit、TextMate、TextPad、JEdit、SciTE、Nano、Notepad++、Geany、SlickEdit、IntelliJ IDEA 和 Sublime Text 2。
你可以將 Linux 的文本編輯器 GEdit 改造成一個很好的 Go 開發工具,詳見頁面:http://gohelp.wordpress.com/。
Sublime Text 是一個革命性的跨平臺(Linux、Mac OS X、Windows)文本編輯器,它支持編寫非常多的編程語言代碼。對于 Go 而言,它有一個插件叫做GoSublime 來支持代碼補全和代碼模版。
這里還有一些更加高級的 Go 開發工具,其中一些是以插件的形式利用本身是作為開發 Java 的工具。
IntelliJ Idea Plugin 是一個 IntelliJ IDEA 的插件,具有很好的操作體驗和代碼補全功能。
LiteIDE 這是一款專門針對 Go 開發的集成開發環境,在編輯、編譯和運行 Go 程序和項目方面都有非常好的支持。同時還包括了對源代碼的抽象語法樹視圖和一些內置工具(此開發環境由國人 vfc 大叔開發)。
GoClipse 是一款 Eclipse IDE 的插件,擁有非常多的特性以及通過 GoCode 來實現代碼補全功能。
如果你對集成開發環境都不是很熟悉,那就使用 LiteIDE 吧,另外使用 GoClipse 或者 IntelliJ Idea Plugin 也是不錯的選擇。
代碼補全 一般都是通過內置 GoCode 實現的(如:LieteIDE、GoClipse),如果需要手動安裝 GoCode,在命令行輸入指令go get -u github.com/nsf/gocode 即可(務必事先配置好 Go 環境變量)。
接下來會對這三個集成開發環境做更加詳細的說明。
調試器
應用程序的開發過程中調試是必不可少的一個環節,因此有一個好的調試器是非常重要的,可惜的是,Go 在這方面的發展還不是很完善。目前可用的調試器是 gdb,最新版均以內置在集成開發環境 LiteIDE 和 GoClipse 中,但是該調試器的調試方式并不靈活且操作難度較大。
如果你不想使用調試器,你可以按照下面的一些有用的方法來達到基本調試的目的:
在合適的位置使用打印語句輸出相關變量的值(print/println 和 fmt.Print/fmt.Println/fmt.Printf)。
在 fmt.Printf 中使用下面的說明符來打印有關變量的相關信息:
- %+v 打印包括字段在內的實例的完整信息
- %#v 打印包括字段和限定類型名稱在內的實例的完整信息
- %T 打印某個類型的完整說明
使用 panic 語句來獲取棧跟蹤信息(直到 panic 時所有被調用函數的列表)。
使用關鍵字 defer 來跟蹤代碼執行過程。
構建并運行 Go 程序
在大多數 IDE 中,每次構建程序之前都會自動調用源碼格式化工具 gofmt 并保存格式化后的源文件。如果構建成功則不會輸出任何信息,而當發生編譯時錯誤時,則會指明源碼中具體第幾行出現了什么錯誤,如:a declared and not used。一般情況下,你可以雙擊 IDE 中的錯誤信息直接跳轉到發生錯誤的那一行。
如果程序執行一切順利并成功退出后,將會在控制臺輸出 Program exited with code 0。
從 Go 1 版本開始,使用 Go 自帶的更加方便的工具來構建應用程序:
- go build 編譯并安裝自身包和依賴包
- go install 安裝自身包和依賴包
格式化代碼
Go 開發團隊不想要 Go 語言像許多其它語言那樣總是在為代碼風格而引發無休止的爭論,浪費大量寶貴的開發時間,因此他們制作了一個工具:go fmt(gofmt)。這個工具可以將你的源代碼格式化成符合官方統一標準的風格,屬于語法風格層面上的小型重構。遵循統一的代碼風格是 Go 開發中無可撼動的鐵律,因此你必須在編譯或提交版本管理系統之前使用gofmt 來格式化你的代碼。
盡管這種做法也存在一些爭論,但使用 gofmt 后你不再需要自成一套代碼風格而是和所有人使用相同的規則。這不僅增強了代碼的可讀性,而且在接手外部 Go 項目時,可以更快地了解其代碼的含義。此外,大多數開發工具也都內置了這一功能。
Go 對于代碼的縮進層級方面使用 tab 還是空格并沒有強制規定,一個 tab 可以代表 4 個或 8 個空格。在實際開發中,1 個 tab 應該代表 4 個空格,而在本身的例子當中,每個 tab 代表 8 個空格。至于開發工具方面,一般都是直接使用 tab 而不替換成空格。
在命令行輸入 gofmt –w program.go 會格式化該源文件的代碼然后將格式化后的代碼覆蓋原始內容(如果不加參數 -w 則只會打印格式化后的結果而不重寫文件);gofmt -w *.go 會格式化并重寫所有 Go 源文件;gofmt map1 會格式化并重寫 map1 目錄及其子目錄下的所有 Go 源文件。
gofmt 也可以通過在參數 -r 后面加入用雙引號括起來的替換規則實現代碼的簡單重構,規則的格式:<原始內容> -> <替換內容>。
實例:
gofmt -r '(a) -> a' –w *.go上面的代碼會將源文件中沒有意義的括號去掉。
gofmt -r 'a[n:len(a)] -> a[n:]' –w *.go上面的代碼會將源文件中多余的 len(a) 去掉。( 譯者注:了解切片(slice)之后就明白這為什么是多余的了 )
gofmt –r 'A.Func1(a,b) -> A.Func2(b,a)' –w *.go上面的代碼會將源文件中符合條件的函數的參數調換位置。
如果想要了解有關 gofmt 的更多信息,請訪問該頁面:http://golang.org/cmd/gofmt/。
生成代碼文檔
go doc 工具會從 Go 程序和包文件中提取頂級聲明的首行注釋以及每個對象的相關注釋,并生成相關文檔。
它也可以作為一個提供在線文檔瀏覽的 web 服務器,http://golang.org 就是通過這種形式實現的。
一般用法
- go doc package 獲取包的文檔注釋,例如:go doc fmt 會顯示使用 godoc 生成的fmt 包的文檔注釋。
- go doc package/subpackage 獲取子包的文檔注釋,例如:go doc container/list。
- go doc package function 獲取某個函數在某個包中的文檔注釋,例如:go doc fmt Printf 會顯示有關fmt.Printf() 的使用說明。
這個工具只能獲取在 Go 安裝目錄下 .../go/src 中的注釋內容。此外,它還可以作為一個本地文檔瀏覽 web 服務器。在命令行輸入godoc -http=:6060,然后使用瀏覽器打開http://localhost:6060 后,你就可以看到本地文檔瀏覽服務器提供的頁面。
godoc 也可以用于生成非標準庫的 Go 源碼文件的文檔注釋(第 9.6 章)。
如果想要獲取更多有關 godoc 的信息,請訪問該頁面:http://golang.org/cmd/godoc/(在線版的第三方包godoc 可以使用Go Walker)。
其它工具
Go 自帶的工具集主要使用腳本和 Go 語言自身編寫的,目前版本的 Go 實現了以下三個工具:
- go install 是安裝 Go 包的工具,類似 Ruby 中的 rubygems。主要用于安裝非標準庫的包文件,將源代碼編譯成對象文件。
- go fix 用于將你的 Go 代碼從舊的發行版遷移到最新的發行版,它主要負責簡單的、重復的、枯燥無味的修改工作,如果像 API 等復雜的函數修改,工具則會給出文件名和代碼行數的提示以便讓開發人員快速定位并升級代碼。Go 開發團隊一般也使用這個工具升級 Go 內置工具以及 谷歌內部項目的代碼。go fix 之所以能夠正常工作是因為 Go 在標準庫就提供生成抽象語法樹和通過抽象語法樹對代碼進行還原的功能。該工具會嘗試更新當前目錄下的所有 Go 源文件,并在完成代碼更新后在控制臺輸出相關的文件名稱。
- go test 是一個輕量級的單元測試框架
Go 性能說明
根據 Go 開發團隊和基本的算法測試,Go 語言與 C 語言的性能差距大概在 10%~20% 之間( 譯者注:由于出版時間限制,該數據應為 2013 年 3 月 28 日之前產生 )。雖然沒有官方的性能標準,但是與其它各個語言相比已經擁有非常出色的表現。
如果說 Go 語言的執行效率大約比 C++ 慢 20% 也許更有實際意義。保守估計在相同的環境和執行目標的情況下,Go 程序比 Java 或 Scala 應用程序要快上 2 倍,并比這兩門語言使用少占用 70% 的內存。在很多情況下這種比較是沒有意義的,因為像谷歌這樣擁有成千上萬臺服務器的公司都拋棄 C++ 而開始將 Go 用于生產環境已經足夠說明它本身所具有的優勢。
時下流行的語言大都是運行在虛擬機上,如:Java 和 Scala 使用的 JVM,C# 和 VB.NET 使用的 .NET CLR。盡管虛擬機的性能已經有了很大的提升,但任何使用 JIT 編譯器和腳本語言解釋器的編程語言(Ruby、Python、Perl 和 JavaScript)在 C 和 C++ 的絕對優勢下甚至都無法在性能上望其項背。
如果說 Go 比 C++ 要慢 20%,那么 Go 就要比任何非靜態和編譯型語言快 2 到 10 倍,并且能夠更加高效地使用內存。
其實比較多門語言之間的性能是一種非常猥瑣的行為,因為任何一種語言都有其所擅長和薄弱的方面。例如在處理文本方面,那些只處理純字節的語言顯然要比處理 Unicode 這種更為復雜編碼的語言要出色的多。有些人可能認為使用兩種不同的語言實現同一個目標能夠得出正確的結論,但是很多時候測試者可能對一門語言非常了解而對另一門語言只是大概明白,測試者對程序編寫的手法在一定程度也會影響結果的公平性,因此測試程序應該分別由各自語言的擅長者來編寫,這樣才能得到具有可比性的結果。另外,像在統計學方面,人們很難避免人為因素對結果的影響,所以這在嚴格意義上并不是科學。還要注意的是,測試結果的可比性還要根據測試目標來區別,例如很多發展十多年的語言已經針對各類問題擁有非常成熟的類庫,而作為一門新生語言的 Go 語言,并沒有足夠的時間來推導各類問題的最佳解決方案。如果你想獲取更多有關性能的資料,請訪問 Computer Language Benchmark Game(詳見引用 27)。
這里有一些評測結果:
-
比較 Go 和 Python 在簡單的 web 服務器方面的性能,單位為傳輸量每秒:
原生的 Go http 包要比 web.py 快 7 至 8 倍,如果使用 web.go 框架則稍微差點,比 web.py 快 6 至 7 倍。在 Python 中被廣泛使用的 tornado 異步服務器和框架在 web 環境下要比 web.py 快很多,Go 大概只比它快 1.2 至 1.5 倍(詳見引用 26)。
-
Go 和 Python 在一般開發的平均水平測試中,Go 要比 Python 3 快 25 倍左右,少占用三分之二的內存,但比 Python 大概多寫一倍的代碼(詳見引用 27)。
-
根據 Robert Hundt(2011 年 6 月,詳見引用 28)的文章對 C++、Java、Go 和 Scala,以及 Go 開發團隊的反應(詳見引用 29),可以得出以下結論:
- Go 和 Scala 之間具有更多的可比性(都使用更少的代碼),而 C++ 和 Java 都使用非常冗長的代碼。
- Go 的編譯速度要比絕大多數語言都要快,比 Java 和 C++ 快 5 至 6 倍,比 Scala 快 10 倍。
- Go 的二進制文件體積是最大的(每個可執行文件都包含 runtime)。
- 在最理想的情況下,Go 能夠和 C++ 一樣快,比 Scala 快 2 至 3 倍,比 Java 快 5 至 10 倍。
- Go 在內存管理方面也可以和 C++ 相媲美,幾乎只需要 Scala 所使用的一半,比 Java 少 4 倍左右。
與 C 進行交互
工具 cgo 提供了對 FFI(外部函數接口)的支持,能夠使用 Go 代碼安全地調用 C 語言庫,你可以訪問 cgo 文檔主頁:http://golang.org/cmd/cgo。cgo 會替代 Go 編譯器來產生可以組合在同一個包中的 Go 和 C 代碼。在實際開發中一般使用 cgo 創建單獨的 C 代碼包。
如果你想要在你的 Go 程序中使用 cgo,則必須在單獨的一行使用 import "C" 來導入,一般來說你可能還需要 import "unsafe"。
然后,你可以在 import "C" 之前使用注釋(單行或多行注釋均可)的形式導入 C 語言庫(甚至有效的 C 語言代碼),它們之間沒有空行,例如:
// #include <stdio.h> // #include <stdlib.h> import "C"名稱 "C" 并不屬于標準庫的一部分,這只是 cgo 集成的一個特殊名稱用于引用 C 的命名空間。在這個命名空間里所包含的 C 類型都可以被使用,例如 C.uint、C.long 等等,還有 libc 中的函數 C.random() 等也可以被調用。
當你想要使用某個類型作為 C 中函數的參數時,必須將其轉換為 C 中的類型,反之亦然,例如:
var i int C.uint(i) // 從 Go 中的 int 轉換為 C 中的無符號 int int(C.random()) // 從 C 中 random() 函數返回的 long 轉換為 Go 中的 int下面的 2 個 Go 函數 Random() 和 Seed() 分別調用了 C 中的 C.random() 和C.srandom()。
示例 3.2 c1.go
package rand// #include <stdlib.h> import "C"func Random() int {return int(C.random()) }func Seed(i int) {C.srandom(C.uint(i)) }C 當中并沒有明確的字符串類型,如果你想要將一個 string 類型的變量從 Go 轉換到 C 時,可以使用 C.CString(s);同樣,可以使用C.GoString(cs) 從 C 轉換到 Go 中的 string 類型。
Go 的內存管理機制無法管理通過 C 代碼分配的內存。
開發人員需要通過手動調用 C.free 來釋放變量的內存:
defer C.free(unsafe.Pointer(Cvariable))這一行最好緊跟在使用 C 代碼創建某個變量之后,這樣就不會忘記釋放內存了。下面的代碼展示了如何使用 cgo 創建變量、使用并釋放其內存:
示例 3.3 c2.go
package print// #include <stdio.h> // #include <stdlib.h> import "C" import "unsafe"func Print(s string) {cs := C.CString(s)defer C.free(unsafe.Pointer(cs))C.fputs(cs, (*C.FILE)(C.stdout)) }構建 cgo 包
?Makefile 文件(因為我們使用了一個獨立的包),除了使用變量 GOFILES 之外,還需要使用變量 CGOFILES 來列出需要使用 cgo 編譯的文件列表。例如,示例 3.2 中的代碼就可以使用包含以下內容的 Makefile 文件來編譯,你可以使用 gomake 或 make:
include $(GOROOT)/src/Make.inc TARG=rand CGOFILES=\ c1.go\ include $(GOROOT)/src/Make.pkg與 C++ 進行交互
SWIG(簡化封裝器和接口生成器)支持在 Linux 系統下使用 Go 代碼調用 C 或者 C++ 代碼。這里有一些使用 SWIG 的注意事項:
- 編寫需要封裝的庫的 SWIG 接口。
- SWIG 會產生 C 的存根函數。
- 這些庫可以使用 cgo 來調用。
- 相關的 Go 文件也可以被自動生成。
這類接口支持方法重載、多重繼承以及使用 Go 代碼實現 C++ 的抽象類。
目前使用 SWIG 存在的一個問題是它無法支持所有的 C++ 庫,比如說它就無法解析 TObject.h。
參考資料:
1) 《The Way to Go》的中文版:https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/directory.md)
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀
總結
以上是生活随笔為你收集整理的golang语言-1-go普及知识的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Golang 解决no buildabl
- 下一篇: WebService与使用风格RPC/S