GO語言————3、編輯器、整合開發環境與其它工具

FLy_鵬程萬里發表於2018-06-26

無意中發現了一個巨牛巨牛的人工智慧教程,忍不住分享一下給大家。教程不僅是零基礎,通俗易懂,小白也能學,而且非常風趣幽默,還時不時有內涵段子,像看小說一樣,哈哈~我正在學習中,覺得太牛了,所以分享給大家。點這裡可以跳轉到教程!

3.1 Go 開發環境的基本要求

這裡有一個你可以期待你用來開發 Go 的整合開發環境有哪些特性的列表,從而替代你使用文字編輯器寫程式碼和命令列編譯與連結程式的方式。

 

  • 語法高亮是必不可少的功能,這也是為什麼每個開發工具都提供配置檔案來實現自定義配置的原因。
  • 可以自動儲存程式碼,至少在每次編譯前都會儲存。
  • 可以顯示程式碼所在的行數。
  • 擁有較好的專案檔案縱覽和導航能力,可以同時編輯多個原始檔並設定書籤,能夠匹配括號,能夠跳轉到某個函式或型別的定義部分。
  • 完美的查詢和替換功能,替換之前最好還能預覽結果。
  • 可以註釋或取消註釋選中的一行或多行程式碼。
  • 當有編譯錯誤時,雙擊錯誤提示可以跳轉到發生錯誤的位置。
  • 跨平臺,能夠在 Linux、Mac OS X 和 Windows 下工作,這樣就可以專注於一個開發環境。
  • 最好是免費的,不過有些開發者還是希望能夠通過支付一定金額以獲得更好的開發環境
  • 最好是開源的。
  • 能夠通過外掛架構來輕易擴充套件和替換某個功能。
  • 儘管整合開發環境本身就是非常複雜的,但一定要讓人感覺操作方便。
  • 能夠通過程式碼模版來簡化編碼過程從而提升編碼速度。
  • 使用 Go 專案的概念來瀏覽和管理專案中的檔案,同時還要擁有構建系統的概念,這樣才能更加方便的構建、清理或執行我們建立的程式或專案。構建出的程式需要能夠通過命令列或 IDE 內部的控制檯執行擁有斷點、檢查變數值、單步執行、逐過程執行標識庫中程式碼的能力。
  • 能夠方便的存取最近使用過的檔案或專案。
  • 擁有對包、型別、變數、函式和方法的智慧程式碼補全的功能。
  • 能夠對專案或包中的程式碼建立抽象語法樹檢視(AST-view)。
  • 內建 Go 的相關工具。
  • 能夠方便完整地查閱 Go 文件。
  • 能夠方便地在不同的 Go 環境之間切換。
  • 能夠匯出不同格式的程式碼檔案,如:PDF,HTML 或格式化後的程式碼。
  • 針對一些特定的專案有專案模板,如:Web 應用,App Engine 專案,從而能夠更快地開始開發工作。
  • 具備程式碼重構的能力。
  • 整合像 hg 或 git 這樣的版本控制工具。
  • 整合 Google App Engine 開發及除錯的功能。

3.2 編輯器和整合開發環境

這些編輯器包含了程式碼高亮和其它與 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 環境變數) 。

接下來會對這三個整合開發環境做更加詳細的說明。

3.2.1 LiteIDE

這款 IDE 的當前最新版本號為 X27,你可以從 GitHub 頁面獲取詳情。

LiteIDE 是一款非常好用的輕量級 Go 整合開發環境(基於 QT、Kate 和 SciTE),包含了跨平臺開發及其它必要的特性,對程式碼編寫、自動補全和執行除錯都有極佳的支援。它採用了 Go 專案的概念來對專案檔案進行瀏覽和管理,它還支援在各個 Go 開發環境之間隨意切換以及交叉編譯的功能。

同時,它具備了抽象語法樹檢視的功能,可以清楚地縱覽專案中的常量、變數、函式、不同型別以及他們的屬性和方法。

 

 

圖 3.1 LiteIDE 程式碼編輯介面和抽象語法樹檢視

 

3.2.2 GoClipse

該款外掛的當前最新版本號為 0.9.1,你可以從 GitHub 頁面獲取詳情。

其依附於著名的 Eclipse 這個大型開發環境,雖然需要安裝 JVM 執行環境,但卻可以很容易地享有 Eclipse 本身所具有的諸多功能。這是一個非常好的編輯器,完善的程式碼補全、抽象語法樹檢視、專案管理和程式除錯功能。

 

圖 3.2 GoClipse 程式碼編輯介面、抽象語法樹檢視和專案管理

 

 

3.3 偵錯程式

應用程式的開發過程中除錯是必不可少的一個環節,因此有一個好的偵錯程式是非常重要的,可惜的是,Go 在這方面的發展還不是很完善。目前可用的偵錯程式是 gdb,最新版均以內建在整合開發環境 LiteIDE 和 GoClipse 中,但是該偵錯程式的除錯方式並不靈活且操作難度較大。

如果你不想使用偵錯程式,你可以按照下面的一些有用的方法來達到基本除錯的目的:

  1. 在合適的位置使用列印語句輸出相關變數的值(print/println 和 fmt.Print/fmt.Println/fmt.Printf)。

  2. 在 fmt.Printf 中使用下面的說明符來列印有關變數的相關資訊:

    • %+v 列印包括欄位在內的例項的完整資訊
    • %#v 列印包括欄位和限定型別名稱在內的例項的完整資訊
    • %T 列印某個型別的完整說明
  3. 使用 panic 語句(第 13.2 節)來獲取棧跟蹤資訊(直到 panic 時所有被呼叫函式的列表)。

  4. 使用關鍵字 defer 來跟蹤程式碼執行過程(第 6.4 節)。

3.4 構建並執行 Go 程式

在大多數 IDE 中,每次構建程式之前都會自動呼叫原始碼格式化工具 gofmt 並儲存格式化後的原始檔。如果構建成功則不會輸出任何資訊,而當發生編譯時錯誤時,則會指明原始碼中具體第幾行出現了什麼錯誤,如:a declared and not used。一般情況下,你可以雙擊 IDE 中的錯誤資訊直接跳轉到發生錯誤的那一行。

如果程式執行一切順利併成功退出後,將會在控制檯輸出 Program exited with code 0

從 Go 1 版本開始,使用 Go 自帶的更加方便的工具來構建應用程式:

  • go build 編譯並安裝自身包和依賴包
  • go install 安裝自身包和依賴包

3.5 格式化程式碼

Go 開發團隊不想要 Go 語言像許多其它語言那樣總是在為程式碼風格而引發無休止的爭論,浪費大量寶貴的開發時間,因此他們製作了一個工具:go fmtgofmt)。這個工具可以將你的原始碼格式化成符合官方統一標準的風格,屬於語法風格層面上的小型重構。遵循統一的程式碼風格是 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/

 

 

 

3.6 生成程式碼文件

 

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)。

3.7 其它工具

Go 自帶的工具集主要使用指令碼和 Go 語言自身編寫的,目前版本的 Go 實現了以下三個工具:

  • go install 是安裝 Go 包的工具,類似 Ruby 中的 rubygems。主要用於安裝非標準庫的包檔案,將原始碼編譯成物件檔案。
  • go fix 用於將你的 Go 程式碼從舊的發行版遷移到最新的發行版,它主要負責簡單的、重複的、枯燥無味的修改工作,如果像 API 等複雜的函式修改,工具則會給出檔名和程式碼行數的提示以便讓開發人員快速定位並升級程式碼。Go 開發團隊一般也使用這個工具升級 Go 內建工具以及 谷歌內部專案的程式碼。go fix 之所以能夠正常工作是因為 Go 在標準庫就提供生成抽象語法樹和通過抽象語法樹對程式碼進行還原的功能。該工具會嘗試更新當前目錄下的所有 Go 原始檔,並在完成程式碼更新後在控制檯輸出相關的檔名稱。
  • go test 是一個輕量級的單元測試框架(第 13 章)。

 

 

 

3.8 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 倍左右。

3.9 與其它語言進行互動

3.9.1 與 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.uintC.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 包

你可以在使用將會在第 9.5 節講到的 Makefile 檔案(因為我們使用了一個獨立的包),除了使用變數 GOFILES 之外,還需要使用變數 CGOFILES 來列出需要使用 cgo 編譯的檔案列表。例如,示例 3.2 中的程式碼就可以使用包含以下內容的 Makefile 檔案來編譯,你可以使用 gomake 或 make:

include $(GOROOT)/src/Make.inc
TARG=rand
CGOFILES=\
c1.go\
include $(GOROOT)/src/Make.pkg

3.9.2 與 C++ 進行互動

SWIG(簡化封裝器和介面生成器)支援在 Linux 系統下使用 Go 程式碼呼叫 C 或者 C++ 程式碼。這裡有一些使用 SWIG 的注意事項:

  • 編寫需要封裝的庫的 SWIG 介面。
  • SWIG 會產生 C 的存根函式。
  • 這些庫可以使用 cgo 來呼叫。
  • 相關的 Go 檔案也可以被自動生成。

這類介面支援方法過載、多重繼承以及使用 Go 程式碼實現 C++ 的抽象類。

目前使用 SWIG 存在的一個問題是它無法支援所有的 C++ 庫,比如說它就無法解析 TObject.h。

相關文章