1. 程式人生 > 實用技巧 >go築基篇(一)--入門

go築基篇(一)--入門

【1】基礎知識

一、簡介

Go是一個快速的靜態型別編譯型語言,Go語言具有很強的表達能力,它簡潔、清晰而高效。Go語言(或 Golang)起源於 2007 年,並在 2009 年正式對外發布。Go語言有時候被描述為“C 類似語言”,或者是“21 世紀的C語言”。

Go 從C語言繼承了相似的表示式語法、控制流結構、基礎資料型別、呼叫引數傳值、指標等很多思想,還有C語言一直所看中的編譯後機器碼的執行效率以及和現有作業系統的無縫適配。

Go語言沒有類和繼承的概念,它通過介面(interface)的概念來實現多型性。Go語言有一個清晰易懂的輕量級型別系統,在型別之間也沒有層級之說。因此可以說Go語言是一門混合型的語言。

很多重要的開源專案都是使用Go語言開發的,其中包括Docker、 Kubernetes。

Go 使用編譯器來編譯程式碼。編譯器將原始碼編譯成二進位制(或位元組碼)格式;

在編譯程式碼時,編譯器檢查錯誤、優化效能並輸出可在不同平臺上執行的二進位制檔案。要建立並執行 Go 程式,程式設計師必須執行如下步驟。

  1. 編輯 Go 程式;
  2. 儲存檔案;
  3. 編譯程式;
  4. 執行編譯得到的可執行檔案。

這不同於 Python、Ruby 和 JavaScript 等語言,它們不包含編譯步驟。Go 自帶了編譯器,因此無須單獨安裝編譯器。

二、為什麼會有go語言?

go語言的所有設計者都說,設計Go語言是因為 C++ 給他們帶來了挫敗感。在 Google I/O 2012 的 Go 設計小組見面會上,Rob Pike 是這樣說的:我們做了大量的 C++ 開發,厭煩了等待編譯完成,儘管這是玩笑,但在很大程度上來說也是事實。

在Go語言出現之前,開發者們總是面臨非常艱難的抉擇,究竟是使用執行速度快但是編譯速度並不理想的語言(如:C++),還是使用編譯速度較快但執行效率不佳的語言(如:.NET、Java),

或者說開發難度較低但執行速度一般的動態語言呢?

顯然,Go語言在這 3 個條件之間做到了最佳的平衡:快速編譯,高效執行,易於開發。

Go語言支援交叉編譯,比如說你可以在執行 Linux 系統的計算機上開發可以在 Windows 上執行的應用程式。

這是第一門完全支援 UTF-8 的程式語言,這不僅體現在它可以處理使用 UTF-8 編碼的字串,就連它的原始碼檔案格式都是使用的 UTF-8 編碼。

Go語言做到了真正的國際化。

三、go語言優勢

容易學習

go語言語法特性簡單,容易上手

效率

go語言編譯非常快速,而且開發的效率、執行的效率也都非常的高。相較與java、c++這些比較呆滯的編譯速度,go的編譯速度是一個主要的效率優勢。

C語言的理念是信任程式設計師,保持語言的小巧,不遮蔽底層,並且底層友好,關注語言的執行效率和效能。而python的姿態是使用盡量少的程式碼完成儘量多的事。

go語言想要把c和python統一起來,所以go語言有著接近c的執行效率和接近python的開發效率

出生名門、血統純正

go語言出自google公司,設計者都是大佬

並行和非同步程式設計幾乎無痛點

go語言的goroutine和channel這2個神器簡直就是併發和非同步程式設計的福音,不像c、c++、java、python、javascript等併發和非同步方式比較複雜,而且容易出錯,go解決了這個問題,而且非常優雅和劉暢。

goroutine以及基於channel的併發性方法使其非常容易使用所有可用的cpu核心,並且處理併發的IO

go是為大資料微服務併發而生的一種程式語言。

自由高效

go可以利用組合的思想實現無侵入式的介面設計。go語言支援當前所有的程式設計正規化:程序式程式設計、面向物件程式設計、面向介面程式設計、函數語言程式設計,程式設計師可以各取所需,自由組合

強大的標準庫

包括網際網路應用、系統程式設計、網路程式設計,go裡面標準庫基本上已經非常穩定了

部署方便

go通過二進位制檔案拷貝進行部署,部署很方便,所以現在有很多人使用go語言開發運維程式

穩定性

go擁有強大的編譯檢查、嚴格的編碼規範和完整的軟體生命週期工具,具有很強的穩定性。

go提供了各個環節的軟體生命週期工具:gotool、gofmt、gotest等等,可以進行開發、測試、部署、維護等等

四、go語言特性

併發程式設計

go語言併發程式設計方面比其它語言要簡潔不少,這一點是其進入高併發、高效能場景的重要籌碼。go的併發執行單元是一種稱為gorountine的協程。

協程又稱微執行緒,比執行緒更輕量,開銷更小,效能更高,操作起來非常簡單。在同一臺機器上可以使用關鍵字go啟動成千上萬個協程,協程之間一般由應運程式顯示實現呼叫,上下文切換無需下到核心層,高效不少。協程間通訊靠獨有的channel機制實現。

記憶體分配

在初始化階段先分配一塊大記憶體區域,大記憶體被切分成各個大小等級的塊,放入不同的空閒list中。物件分配空間時從空閒list中取出大小合適的記憶體塊,記憶體回收時會把不用的記憶體重新放回空閒list,空閒記憶體會按照一定策略合併以減少碎片

記憶體回收(GC)

記憶體自動回收,再也不需要開發人員管理記憶體;

GC過程:先掃描所有物件判活,把可回收物件在一段bitmap區中標記下來,接著立即恢復服務,同時啟一個專門的gorountine,回收記憶體到空閒list中以備複用,物理釋放由專門的執行緒定期執行。GC瓶頸在於每次都要掃描所有物件來判活,遮掩會導致待收集的物件越多速度越慢,但GC的效能會隨著版本的不斷更新而不斷優化

編譯

go語言編譯速度非常快,目前go語言具有2種編譯器:一種是建立在Gcc基礎上的Gccgo,另一種是分別針對x64、x86計算機的一套編譯器。由於go語言絕大多數第三方開源庫都在github上,在程式碼的import中加上對應的github路徑就可以使用了,庫會預設下載到工程的pkg目錄下。編譯時會檢查程式碼中所有實體使用情況,凡是沒有使用到的package或變數都會編譯不通過,這是go語言比較嚴謹的一面。

網路程式設計

由於go語言誕生在網際網路時代,因此它天生具備了去中心化、分散式等特性,具體表現之一就是提供了豐富便捷的網路程式設計介面:

socket用net.Dial(基於tcp/udp,封裝了傳統的connect、listen、accept等介面)

http用http.Get/Post()

rpc用client.Call('類名.方法名',args,&reply)

自帶高效能httpServer,只需要幾行程式碼就能得到一個基於協程的高效能web服務

函式多返回值

在c、c++,包括其它一些高階語言是不支援多返回值的,在c語言中一般將返回值定義成一個結構體或通過函式引數引用的形式進行返回,而在go語言中支援函式多返回值

語言互動性

語言互動性指本語言是否能和其他語言進行互動,比如可以呼叫其它程式語言的庫。

go語言可以和c程式互動,在go語言中直接重用了大部分c的模組,這也成為Cgo,Cgo允許開發者混合編寫C語言程式碼,然後Cgo工具可以將這些混合的c程式碼提取並生成對於c功能的呼叫包裝程式碼,開發者可以完全忽略c語言和go語言的邊界是如何跨越的

異常處理

go語言不止try....catch..這樣的異常解決方式,因為覺著會增加程式碼量,而且會被濫用,不管多小的異常都丟擲。go語言提供的異常處理方式是:

如果是普通異常,檢視被呼叫方法返回的error物件;如果是嚴重異常,指的是中斷性panic(比如除0),使用defer.....recover....panic機制來捕獲處理,嚴重異常一般由go語言內部自動丟擲,避免傳統try....catch...寫的匯出都是的情況,

當然使用者也可以使用panic('xxxxxxx')主動丟擲,只是這樣就使這一套機制退化成結構化異常機制了

型別推導

在定義變數時支援varage=10這樣的語法,讓go語言看上去有點像動態型別語言,但go語言實際上是強型別的,前面的定義會被自動推匯出是int型別。

inerface介面

一個型別只要實現了某個interface的所有方法,無需顯示去繼承即可實現該interface

defer機制

通過該關鍵字可以指定需要延遲持執行的邏輯體,在函式體return前或者出現panic時執行,這種機制非常適合善後邏輯處理,比如可以儘早避免可能出現的資源洩露問題。defer在很大程度上可以簡化程式設計,並且在語言描述上顯得更為自然,極大的增強了程式碼的可讀性

把相同功能的程式碼放到一個目錄,稱之為包。包可以被其它包import引用,main包是用來生成可執行檔案,每個程式只有一個main包。包的主要用途是提高程式碼的可複用性。

Go語言是使用包來組織原始碼的,包(package)是多個 Go 原始碼的集合,是一種高階的程式碼複用方案。Go語言中為我們提供了很多內建包,如 fmt、os、io 等。

交叉編譯

可以在執行linux系統的計算機上,開發執行windows下執行的應用程式

五、技術發展的核心要素

一個技術能否發展起來主要看三點:

有沒有一個比較好的社群

像c、c++、java、python等的生態圈都是非常豐富和火爆的,尤其是有許多商業機構參與的社群,比如linux社群就更加人氣爆棚了

有沒有一個工業化的標準

像c、c++、java都有標準化組織的,尤其是java,它在架構上還搞出了像J2EE這樣企業級標準

有沒有一個或多個殺手級應運

比如php是linux時代第一個殺手級解決方案lnmp中的關鍵技術。go語言殺手級應運是docker,而docker的生態圈這幾年完全爆棚了

學習曲線是否低,上手是否快

有沒有一個不錯的提高開發效率的框架

有沒有一個或多個巨型公司作為後盾

比如java和linux後面的IBM和sun。go語言有google這個世界一流公司在後面

有沒有解決軟體開發中的痛點

比如java,解決了c、c++中的記憶體管理問題。go語言解決了併發程式設計和寫底層應運開發效率的痛點

【2】go環境搭建與基本使用

一、下載安裝包並安裝

正規下載地址:https://golang.org/dl/,但需要翻牆

可訪問下載地址:https://golang.google.cn/dl/

下載完執行安裝即可,我是把go安裝到了d盤

把D:\Go\bin新增到全域性環境編排path中

編輯test.go

package main
import "fmt"
func main() {
   fmt.Println("Hello, World!")
}

執行命令go run test.go

二、安裝go整合開發工具(IDE)

go繼承開發工具有,GoLand、LiteIDE、Eclipse等,以下講解如何安裝GoLand開發工具

官網下載地址(打不開,需要翻牆):https://www.jetbrains.com/go/download/other.html

(推薦)直接複製本條連結到迅雷中下載:https://download.jetbrains.com/go/goland-2019.2.3.exe

下載破解補丁:http://c.biancheng.net/uploads/course/go/Goland_Crack_Sinicization.zip

安裝完後,開啟工具

到這一步退出,把Goland_Crack_Sinicization.zip裡解壓檔案jetbrains-agent.jar拷到C:\Program Files\JetBrains\GoLand 2019.2.3\bin目錄,在bin 目錄下“goland.exe.vmoptions”和“goland64.exe.vmoptions”兩個檔案末尾加上

-javaagent:C:\Program Files\JetBrains\GoLand 2019.2.3\bin\jetbrains-agent.jar

然後開啟JetBrains GoLand 2019.2.3 x64,Licesnse server輸入https://fls.jetbrains-agent.com即可

漢化

把Goland_Crack_Sinicization.zip裡resources_cn.jar複製到 Goland 安裝目錄下的 lib 目錄中(C:\Program Files\JetBrains\GoLand 2019.2.3\lib),

在 lib 目錄中找到“resources_en.jar”檔案,它是 Goland 內建的一個英文補丁,這裡需要將它刪除或者重新命名(resources_en.jar-),建議大家選擇重新命名的方式,因為想要恢復英文的話還需要用到它,

執行 Goland ,你會發現 Goland 中的選單已經變成我們熟悉的中文了

【3】執行go程式

一、go目錄

$GOPATH 目錄約定有三個子目錄:

1.src 存放原始碼(比如:.go .c .h .s等)
2.pkg 編譯後生成的檔案(比如:.a)
3.bin 編譯後生成的可執行檔案(為了方便,可以把此目錄加入到 $PATH 變數中,如果有多個gopath,那麼使用${GOPATH//://bin:}/bin新增所有的bin目錄)

以後自己新建應用或者一個程式碼包都是在src目錄下新建一個資料夾,資料夾名稱一般是程式碼包名稱,當然也允許多級目錄,例如在src下面新建了目錄$GOPATH/src/github.com/astaxie/beedb 那麼這個包路徑就是“github.com/astaxie/beedb”,包名稱是最後一個目錄beedb

注意:一般建議package的名稱和目錄名保持一致

二、GOPATH配置

GOPATH 是 Go語言中使用的一個環境變數,它使用絕對路徑提供專案的工作目錄。GOPATH 適合處理大量 Go語言原始碼、多個包組合而成的複雜工程。

在 Go 1.8 版本之前,GOPATH 環境變數預設是空的。從 Go 1.8 版本開始,Go 開發包在安裝完成後,將 GOPATH 賦予了一個預設的目錄,參見下表。

在 GOPATH 指定的工作目錄下,程式碼總是會儲存在 $GOPATH/src 目錄下,bin 和 pkg 目錄的內容都可以由 src 目錄生成。

在工程經過 go buildgo installgo get 等指令後,會將產生的二進位制可執行檔案放在 $GOPATH/bin 目錄下,生成的中間快取檔案會被儲存在 $GOPATH/pkg

GOPATH分類:

全域性GOPATH(Global GOPATH):

如我的專案名叫test,在D:\go_www\test下,則GOPATH的全域性環境變數設定為D:\go_www\test

如果在這個專案test的src原始檔下有個檔案hello需要編譯

這樣我可以在任何位置執行goinstallhello,或在D:\go_www\test\src\hello下直接執行goinstall,即可在src的同級目錄bin下生成hello.exe可執行檔案

gobuildgoinstall類似,只是gobuild在哪個目錄執行,生成的可執行檔案就會生成在哪個目錄,而不會存於與src同級的bin目錄

缺點:某專案路徑在 /home/davy/projectA ,將該目錄設定為全域性GOPATH。

隨著開發進行,需要再次獲取一份工程專案的原始碼,此時原始碼儲存在 /home/davy/projectB ,如果此時需要編譯 projectB 的專案,又需要重新設定全域性GOPATH,比較麻煩,

若開發者忘記設定 GOPATH 而直接使用命令列編譯,編譯完成後,開發者就會將錯誤的工程版本釋出到外網。

因此建議大家無論是使用命令列或者使用整合開發環境編譯 Go 原始碼時,GOPATH 跟隨專案設定

專案GOPATH(Project GOPATH):

Project GOPATH 代表專案所使用的 GOPATH,該設定會被儲存在工作目錄的 .idea 目錄下,不會被設定到環境變數的 GOPATH 中,但會在編譯時使用到這個目錄。

建議在開發時只填寫專案 GOPATH,每一個專案儘量只設置一個 GOPATH,不使用多個 GOPATH 和全域性的 GOPATH。

建議開發者不要設定全域性的 GOPATH,而是隨專案設定 GOPATH

三、簡單使用

在/src/test/hello目錄下,新建hello.go

package main //宣告包main
import "fmt" //匯入包fmt,實現I/O格式化輸入輸出
func main() {  //main函式
    fmt.Println("hello world")
}

編譯生成二進位制檔案

go install hello

注意:

1、一個資料夾下的所有原始碼檔案只能屬於同一個包。在同一個包下的檔案都屬於同一個工程的檔案,彼此之間不需要使用import引入就能直接使用

2、包名為 main 的包為應用程式的入口包,編譯不包含 main 包的原始碼檔案時不會得到可執行檔案。main函式所在包的宣告必須是main

3、一般包的名稱就是其原始檔所在目錄的名稱,雖然Go語言沒有強制要求包名必須和其所在的目錄名同名,但還是建議包名和所在目錄同名,這樣結構更清晰

4、匯入的包名需要使用雙引號包裹起來

5、包名是從GOPATH/src/後開始計算的,使用/進行路徑分隔

參考資料:

千鋒教育100集線上視訊教程

https://www.bilibili.com/video/BV1Db411s7in?p=8

千鋒go語言全套視訊教程

https://www.bilibili.com/read/cv3742048

go語言入門教程文件

http://c.biancheng.net/golang/