2019-06-03+05 go語言的進階學習 一

一、熟悉Go語言運行環境、包管理工具(手動裝一下Go環境并從零運行一個依賴第三方庫的Go程序)

go modules是官方提倡的新的包管理,乃至項目管理機制,可以不再需要GOPATH的存在。

1、go module 的初始化

golang提供了一個 環境變量“GO111MODULE”,默認值為auto,如果當前目錄里有go.mod文件,就使用 go modules, 否則就使用舊的GOPATH和vendor機制,因為在modules機制下 go get 只會下載 go modules,這一行為會在以后版本中成為默認值,這里我們保持auto即可,如果你想直接使用modules而不需要從GOPATH過度,那么把“GO111MODULE”設置為 on 。

modules和傳統的GOPATH不同,不需要包含例如src,bin這樣的子目錄,一個源代碼目錄甚至是空目錄都可以作為module,只要其中包含有go.mod文件。
在新建的文件夾中寫好依賴了第三方包的go程序,即 main.go
在該文件夾下 通過 ls 命令,可以查看到 目前只有 main.go 文件

(1)初始化modules,需要用到如下命令(前提是已經安裝配置好golang1.11)

go mod init {module name}

我們的module叫test,所以

go mod init test

初始化完成后會在目錄下生成一個 go.mod 文件,里面內容只有一行“ module test”。

(2)包管理 當我們使用 go build,go test 和 go list 時,go 會自動更新 go.mod 文件,將依賴關系寫入其中。
使用如下命令會自動更新依賴關系,并將包下載放入 cache。

go mod tidy

運行完這個命令后,文件夾中會多一個 go.sum 文件。
go.sum文件中主要是我們直接引用的package和它自身需要所依賴的版本記錄,go modules 就是根據這些去找到需要的packages的。

btw,如果我們不做任何修改,默認會使用最新的包版本,如果包打過tag,那么就會使用最新的那個tag對應的版本。

**(3)使用 go build 來編譯我們的代碼

go build -mod=readonly

在這個模式下任何會導致依賴關系變動的情況都將導致build失敗,前面提到過build能查找并更新依賴關系,使用這個選項可以檢查依賴關系的變動。
同時,當運行完這個命令以后,文件夾中會生成一個 test 的執行文件,
至此,main.go 的代碼已經成功完成構建,包管理都由 go modules 替我們完成了。

btw,go build -mod=vendor 的意思是忽略cache里的包,只使用vendor目錄里面的版本。

2、包的版本控制

包管理的另外一項重要功能就是包的版本控制。modules同樣可以做到。

btw,在介紹版本控制之前,我們要先明確一點,如果上層目錄和下層目錄的go.mod里有相同的package規則,那么上層目錄的無條件覆蓋下層目錄,目的是為了main module的構建不會被依賴的package所影響。

go.mod 文件內容如下:

module test

require github.com/chromedp/chromedp v0.1.2

前面部分是包的名字,也就是import時需要寫的部分,而空格之后的是版本號,版本號遵循如下規律:

vX.Y.Z-pre.0.yyyymmddhhmmss-abcdefabcdef
vX.0.0-yyyymmddhhmmss-abcdefabcdef
vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdefabcdef
vX.Y.Z

即 版本號+時間戳+hash
我們自己指定版本時只需要制定版本號即可,沒有版本tag的則需要找到對應commit的時間和hash值。
默認使用最新版本的package。

如果我們需要修改包的版本號(比如想使用chromedp 的v0.1.0版本)
1、只需要如下命令:

go mod edit -require="github.com/chromedp/chromedp@v0.1.0"

@后面加上你需要的版本號。go.mod已經修改了:

module test

require github.com/chromedp/chromedp v0.1.0

2、還需要讓go modules 更新依賴,這里我們手動執行go mod tidy 命令,即可切換到v0.1.0版本。

[golang包管理解決之道——go modules初探
再探go modules:使用與細節
用 golang 1.11 module 做項目版本管理

go modules 文檔

二、熟悉Go語言以下內容:

#### 1) 數據類型(string、slice、map)

Go 語言有 3 種數據結構可以讓用戶管理集合數據:數組、切片和映射。了解這些數據結構,一般會從數組開始,因為數組是切片和映射的基礎數據結構。數組存儲的類型可以是內置類型,如整型或者字符串,也可以是某種結構類型。

                 ##### 數組

如果使用...替代數組的長度, Go 語言會根據初始化時數組元素的數量來確定該數組的長度。

// 聲明一個整型數組
// 用具體值初始化每個元素// 容量由初始化值的數量決定
array := [...]int{10, 20, 30, 40, 50}

二維數組

// 聲明一個二維整型數組,兩個維度分別存儲 4 個元素和 2 個元素
var array [4][2]int
// 使用數組字面量來聲明并初始化一個二維整型數組
array := [4][2]int{{10, 11}, {20, 21}, {30, 31}, {40, 41}}
// 聲明并初始化外層數組中索引為 1 個和 3 的元素
array := [4][2]int{1: {20, 21}, 3: {40, 41}}
// 聲明并初始化外層數組和內層數組的單個元素
array := [4][2]int{1: {0: 20}, 3: {1: 41}}

只要類型一致,就可以將多維數組互相賦值,

// 將 array1 的索引為 1 的維度復制到一個同類型的新數組里
var array3 [2]int = array1[1]
// 將外層數組的索引為 1、內層數組的索引為 0 的整型值復制到新的整型變量里
var value int = array1[1][0]

使用指針在函數間傳遞大數組

//使用值傳遞,在函數間傳遞大數組 
//聲明一個需要 8 MB 的數組
var array [1e6]int
// 將數組傳遞給函數 foo
foo(array)// 函數 foo 接受一個 100 萬個整型值的數組
func foo(array [1e6]int) {
...
}

//使用指針在函數間傳遞大數組
// 分配一個需要 8 MB 的數組
var array [1e6]int
// 將數組的地址傳遞給函數 foo
foo(&array)
// 函數 foo 接受一個指向 100 萬個整型值的數組的指針
func foo(array *[1e6]int) {
...
}
                     ##### 切片

切片是圍繞動態數組的概念構建的,可以按需自動增長和縮小。切片的動態增長是通過內置函數 append來實現的。這個函數可以快速且高效地增長切片。還可以通過對切片再次切片來縮小一個切片的大小。因為切片的底層內存也是在連續塊中分配的,所以切片還能獲得索引、迭代以及為垃圾回收優化的好處。

內部實現
切片有3個字段的數據結構,這些數據結構包含 Go 語言需要操作底層數組的元數據。這 3 個字段分別是指向底層數組的指針、切片訪問的元素的個數(即長度)和切片允許增長到的元素個數(即容量)。

是否能提前知道切片需要的容量通常會決定要如何創建切片。
方法一:使用內置的make函數

  1. 使用長度聲明一個字符串切片
// 創建一個字符串切片
// 其長度和容量都是 5 個元素
slice := make([]string, 5)

//如果只指定長度,那么切片的容量和長度相等。

2)使用長度和容量聲明整型切片

// 創建一個整型切片
// 其長度為 3 個元素,容量為 5 個元素
slice := make([]int, 3, 5)

方法二:通過切片字面量來聲明切片

// 創建字符串切片
// 其長度和容量都是 5 個元素
slice := []string{"Red", "Blue", "Green", "Yellow", "Pink"}
// 創建一個整型切片
// 其長度和容量都是 3 個元素
slice := []int{10, 20, 30}

使用索引聲明切片

// 創建字符串切片
// 使用空字符串初始化第 100 個元素
slice := []string{99: ""}

如果在[]運算符里指定了一個值,那么創建的就是數組而不是切片。只有不指定值
的時候,才會創建切片.

創建nil切片

空切片在底層數組包含 0 個元素,也沒有分配任何存儲空間。想表示空集合時空切片很有用,例如,數據庫查詢返回 0 個查詢結果時

// 聲明空切片

// 使用 make 創建空的整型切片
slice := make([]int, 0)
// 使用切片字面量創建空的整型切片
slice := []int{}
使用切片創建切片
// 創建一個整型切片
// 其長度和容量都是 5 個元素
slice := []int{10, 20, 30, 40, 50}
// 創建一個新切片
// 其長度為 2 個元素,容量為 4 個元素
newSlice := slice[1:3]
4K(13Q{_G)2YOLIF`{)Y9FO.png

對底層數組容量是 k 的切片 slice[i:j]來說
長度: j - i
容量: k - i

btw,共享同一底層數組的切片會導致如果修改了其中一個切片的索引的數據,則另外一個對應切片的數據也會被修改。

// 創建一個整型切片
// 其長度和容量都是 5 個元素
slice := []int{10, 20, 30, 40, 50}
// 創建一個新切片
// 其長度是 2 個元素,容量是 4 個元素
newSlice := slice[1:3]
// 修改 newSlice 索引為 1 的元素
// 同時也修改了原來的 slice 的索引為 2 的元素
newSlice[1] = 35

對于 slice[i:j:k] 或 [2:3:4]
長度: j – i 或 3 - 2 = 1
容量: k – i 或 4 - 2 = 2

切片只能訪問到其長度內的元素。切片有額外的容量是很好,但是如果不能把這些容量合并到切片的長度里,這些容量就沒有用處。

                     ##### 映射

映射是一種數據結構,用于存儲一系列無序的鍵值對。
映射里基于鍵來存儲值。
映射功能強大的地方是,能夠基于鍵快速檢索數據。鍵就像索引一樣,指向該鍵關聯的值。

??1.數組是構造切片和映射的基石。
??2.Go 語言里切片經常用來處理數據的集合,映射用來處理具有鍵值對結構的數據。
??3.函數 make 可以創建切片和映射,并指定原始的長度和容量。也可以直接使用切片和映射字面量,或者使用字面量作為變量的初始值。
??4.有容量限制,不過可以使用內置的 append 函數擴展容量。
??5.的增長沒有容量或者任何限制。
??6.函數 len 可以用來獲取切片或者映射的長度。
??7.函數 cap 只能用于切片。
??8.組合,可以創建多維數組和多維切片。也可以使用切片或者其他映射作為映射的值。但是切片不能用作映射的鍵。
??9.片或者映射傳遞給函數成本很小,并且不會復制底層的數據結構

#### 2) 并發編程(goroutine、channel)

當一個函數創建為 goroutine時, Go 會將其視為一個獨立的工作單元。這個單元會被調度到可用的邏輯處理器上執行。
Go 語言的并發同步模型來自一個叫作通信順序進程(Communicating Sequential Processes, CSP)的范型(paradigm)。 CSP 是一種消息傳遞模型,通過在 goroutine 之間傳遞數據來傳遞消息,而不是對數據進行加鎖來實現同步訪問。
用于在 goroutine 之間同步和傳遞數據的關鍵數據類型叫作通道(channel)。

創建goroutine的例子

01// 這個示例程序展示如何創建 goroutine
02 // 以及調度器的行為
03 package main
04
05 import (
06 "fmt"
07 "runtime"
08 "sync"
09 )
10
11 // main 是所有 Go 程序的入口
12 func main() {
13 // 分配一個邏輯處理器給調度器使用
14 runtime.GOMAXPROCS(1)
15
16 // wg 用來等待程序完成
17 // 計數加 2,表示要等待兩個 goroutine
18 var wg sync.WaitGroup
19 wg.Add(2)
20
21 fmt.Println("Start Goroutines")
22
23 // 聲明一個匿名函數,并創建一個 goroutine
24 go func() {
25 // 在函數退出時調用 Done 來通知 main 函數工作已經完成
26 defer wg.Done()
27
28 // 顯示字母表 3 次
29 for count := 0; count < 3; count++ {
30 for char := 'a'; char < 'a'+26; char++ {
31 fmt.Printf("%c ", char)
32 }
33 }
34 }()
35
36 // 聲明一個匿名函數,并創建一個 goroutine
37 go func() {
38 // 在函數退出時調用 Done 來通知 main 函數工作已經完成
39 defer wg.Done()
40
41 // 顯示字母表 3 次
42 for count := 0; count < 3; count++ {
43 for char := 'A'; char < 'A'+26; char++ {
44 fmt.Printf("%c ", char)
45 }
46 }
47 }()
48
49 // 等待 goroutine 結束
50 fmt.Println("Waiting To Finish")
51 wg.Wait()
52
53 fmt.Println("\nTerminating Program")
54 }

關于該程序中涉及到的defer
Defer is used to ensure that a function call is performed later in a program’s execution, usually for purposes of cleanup. defer is often used where e.g. ensure and finally would be used in other languages.

defer的思想類似于C++中的析構函數,不過Go語言中“析構”的不是對象,而是函數,defer就是用來添加函數結束時執行的語句。注意這里強調的是添加,而不是指定,因為不同于C++中的析構函數是靜態的,Go中的defer是動態的。

more

Go 標準庫的 runtime 包里有一個名為GOMAXPROCS的函數,通過它可以指定調度器可用的邏輯處理器的數量。用這個函數,可以給每個可用的物理處理器在
運行的時候分配一個邏輯處理器。

#### 3) socket編程(net包)

#### 4) http編程(http包)

#### 5) json解析(json包以及其它第三方包)

json的簡單介紹
[JSON](JavaScript Object Notation, JS 對象簡譜) 是一種輕量級的數據交換格式。它基于 [ECMAScript] (歐洲計算機協會制定的js規范)的一個子集,采用完全獨立于編程語言的文本格式來存儲和表示數據。簡潔和清晰的層次結構使得 JSON 成為理想的數據交換語言。 易于人閱讀和編寫,同時也易于機器解析和生成,并有效地提升網絡傳輸效率。

#### 6) 流處理(binary包)
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,556評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,463評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,009評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,778評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,218評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,436評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,969評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,795評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,993評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,229評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,659評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,917評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,687評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,990評論 2 374

推薦閱讀更多精彩內容