Go語言開發小技巧&易錯點100例(二)
開啟掘金成長之旅!這是我參與「掘金日新計劃 · 12 月更文挑戰」的第7天,點選檢視活動詳情
往期回顧:
本期看點(技巧類用【技】表示,易錯點用【易】表示):
(1)Go Module中對依賴庫版本的升級與降級【技】
(2)Go goroutine中的異常處理【易】
(3)Go中slice作為引數是值傳遞【技】
正文:
1 Go Module中對依賴庫版本的升級與降級【技】
Go Module引用其他的依賴庫分為兩種方式:
- 引用該庫的某一個tag
- 引用該庫的某一個分支(稱之為偽版本)
因而顯示上也會有差別(大多數情況下),如下:
shell
github.com/coreos/go-semver v0.3.0 //引用tag
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf //引用分支
但是不管是引用tag還是引用分支,指向的都是該倉庫的分支或tag提交最後一個commit時的映象,因而版本的升級與降級的最小顆粒度就是commit
先看針對tag進行升降級:
```shell
檢視該依賴庫的所有版本
go list -m -versions github.com/xuri/excelize/v2
輸出:
github.com/xuri/excelize/v2 v2.0.0 v2.0.1 v2.0.2 v2.1.0 v2.2.0 v2.3.0 v2.3.1 v2.3.2 v2.4.0 v2.4.1 v2.5.0 v2.6.0 v2.6.1
檢視當前專案依賴庫的版本
go list -m github.com/xuri/excelize/v2
輸出:
github.com/xuri/excelize/v2 v2.6.1
指定想要切換到的版本
go get github.com/xuri/excelize/[email protected]
輸出:
go: downloading github.com/xuri/excelize/v2 v2.6.0 go get: downgraded github.com/xuri/excelize/v2 v2.6.1 => v2.6.0 ```
針對分支或commit升降級(前提是知道之前一個commit的偽版本資訊):
比如你之前一個引用的commit是
shell
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
目前是:
shell
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
想要切換回去,可能go get就不是很管用了,那麼就需要使用新的方式:
shell
replace github.com/coreos/go-systemd => github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
即可將依賴的庫指定到想要的commit
PS:偽版本的概念
這種是因為依賴模組的程式碼倉庫上不存在任何tag,所以go get
預設拉取的是master分支最新一次commit對應版本的程式碼,並且在go.mod
檔案裡為模組分配格式為
shell
v0.0.0-[主幹分支最新一次commit的時間]-[commit雜湊值]
2 Go goroutine中的異常處理【易】
首先看一下這種情況:
go
func main() {
waitGroup := sync.WaitGroup{}
waitGroup.Add(1)
go func() {
defer waitGroup.Done()
fmt.Println("Hello goroutine ...")
panic("err")
}()
waitGroup.Wait()
fmt.Println("Hello main ...")
}
執行結果大家猜能不能打印出Hello main ...?
答案:不能
問題產生的原因就是在goroutine中我們沒有進行對可能發生的異常進行處理,當goroutine中發生panic的時候會影響主函式的執行,那麼我們應該如何處理呢?
使用recover處理異常
go
func main() {
waitGroup := sync.WaitGroup{}
waitGroup.Add(1)
go func() {
defer func() {
if e := recover(); e != nil {
fmt.Println("recover panic")
}
waitGroup.Done()
}()
fmt.Println("Hello goroutine ...")
panic("err")
}()
waitGroup.Wait()
fmt.Println("Hello main ...")
}
優化點:
- 注意列印異常日誌
- 使用channel將錯誤資訊返回至主執行緒處理
3 Go中slice作為引數是值傳遞【技】
我們直接來試一下:
```go func Test(list []string) { fmt.Println(list) fmt.Println(unsafe.Pointer(&list)) }
func main() { list := make([]string, 0) list = append(list, "a", "b", "c") fmt.Println(list) fmt.Println(unsafe.Pointer(&list)) Test(list) } ```
輸出結果:
shell
[a b c]
0xc000004078
[a b c]
0xc0000040a8
今天的分享就先到這裡咯~