成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

你有犯過這些 Go 編碼錯誤嗎?

開發 前端
實際上在 Go 中,所有的函數傳遞都是值傳遞。也就是將數組傳遞給函數時,會復制該數組。如果真的是需要傳進函數內修改,可以改用切片。

大家好,我是煎魚。

在用 Go 編程時,總會遇到各種奇奇怪怪的錯誤,國內外已經有許多小伙伴總結過(參考鏈接見參考),感覺都能湊一桌了。

希望對大家有所幫助。

Go 常見錯誤

1. nil Map

問題

在程序中聲明(定義)了一個 map,然后直接寫入數據。如下代碼:

func main() {
var m map[string]string
m["煎魚"] = "進腦子了"
}

輸出結果:

panic: assignment to entry in nil map

會直接拋出一個 panic。

解決方法

解決方法其實就是要聲明并初始化,Go 里標準寫法是調用 make 函數就可以了。如下代碼:

func main() {
m := make(map[string]string)
m["煎魚"] = "下班了"
}

這個問題在初學 Go 時是最容易踩到的錯誤。

2. 空指針的引用

問題

我們在 Go 經常會利用結構體去聲明一系列的方法,他看起來向面向對象中的 ”類“,在業務代碼中非常常見。

如下代碼:

type Point struct {
X, Y float64
}

func (p *Point) Abs() float64 {
return math.Sqrt(p.X*p.X + p.Y*p.Y)
}

func main() {
var p *Point
fmt.Println(p.Abs())
}

這段程序能夠正常運行嗎?正常計算和輸出?

輸出結果:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x10a3143]

goroutine 1 [running]:
main.(*Point).Abs(...)
/Users/eddycjy/awesomeProject/main.go:13
main.main()
/Users/eddycj/awesomeProject/main.go:18 +0x23

直接就恐慌了,由于空指針的引用。

解決方法

如果變量 p 是一個指針,則必須要進行初始化才可以進行調用。如下代碼:

func main() {
var p *Point = new(Point)
fmt.Println(p.Abs())
}

又或是用值對象的方法來解決:

func main() {
var p Point // has zero value Point{X:0, Y:0}
fmt.Println(p.Abs())
}

3. 使用對循環迭代器變量的引用

問題

在 Go 中,循環迭代器變量是一個單一的變量,在每個循環迭代中取不同的值。這如果使用不當,可能會導致非預期的行為。

如下代碼:

func main() {
var out []*int
for i := 0; i < 3; i++ {
out = append(out, &i)
}
fmt.Println("Values:", *out[0], *out[1], *out[2])
fmt.Println("Addresses:", out[0], out[1], out[2])
}

輸出結果是什么。大膽猜想值是 1,2,3,地址都是不一樣的。對嗎?

輸出結果:

Values: 3 3 3
Addresses: 0x40e020 0x40e020 0x40e020

值都是 3,地址都是同一個指向。

解決方法

其中一種解決方法是將循環變量復制到一個新變量中:

 for i := 0; i < 3; i++ {
i := i // Copy i into a new variable.
out = append(out, &i)
}

輸出結果:

Values: 0 1 2
Addresses: 0x40e020 0x40e024 0x40e028

原因是:在每次迭代中,我們將 i 的地址追加到 out 切片中,但由于它是同一個變量,我們實際上追加的是相同的地址,該地址最終包含分配給 i 的最后一個值。

所以只需要拷貝一份,讓兩者脫離關聯就可以了。

4. 在循環迭代器變量上使用 goroutine

問題

在 Go 中進行循環時,我們經常會使用 goroutine 來并發處理數據。最經典的就是會結合閉包來編寫業務邏輯。

如下代碼:

values := []int{1, 2, 3, 4, 5}
for _, val := range values {
go func() {
fmt.Println(val)
}()
}

time.Sleep(time.Second)

但在實際的運行中,上述 for 循環可能無法達到您的預期,你想的可能是順序輸出切片中的值。

輸出的結果是:

5
5
4
5
5

你可能會看到每次迭代打印的最后一個元素,甚至你會發現,每次輸出的結果還不一樣...

如果去掉休眠代碼,會發現 goroutine 可能根本不會開始執行,程序就結束了。

解決方法

這其實就是閉包使用上的一個常見問題,編寫該閉包循環的正確方法是:

values := []int{1, 2, 3, 4, 5}
for _, val := range values {
go func(val int) {
fmt.Println(val)
}(val)
}

通過將 val 作為參數添加到閉包中,在每次循環時,變量 val 都會被存儲在 goroutine 的堆棧中,以確保最終 goroutine 執行時值是對的。

當然,這里還有一個隱性問題。大家總會以為是按順序輸出 1, 2, 3, 4, 5。其實不然,因為 goroutine 的執行是具有隨機性的,沒法確保順序。

注:經常會變形出現在許多 Go 的面試題當中,一旦復雜起來就容易讓人迷惑。

5. 數組不會被改變

問題

切片和數字是我們在 Go 程序中應用最廣泛的數據類型,但他常常會有一些奇奇怪怪的問題。

如下代碼:

func Foo(a [2]int) {
a[0] = 8
}

func main() {
a := [2]int{1, 2}
Foo(a)
fmt.Println(a)
}

輸出結是什么。是 [8 2],對嗎?

輸出結果:

[1 2]

這是為什么,函數里修改了個寂寞?

解決方法

實際上在 Go 中,所有的函數傳遞都是值傳遞。也就是將數組傳遞給函數時,會復制該數組。如果真的是需要傳進函數內修改,可以改用切片。

如下代碼:

func Foo(a []int) {
if len(a) > 0 {
a[0] = 8
}
}

func main() {
a := []int{1, 2}
Foo(a)
fmt.Println(a)
}

輸出結果:

[8 2]

原因是:切片不會存儲任何的數據,他的底層 data 會指向一個底層數組。因此在修改切片的元素時,會修改其底層數組的相應元素,共享同一個底層數組的其他切片會一并修改。

你以為這就萬事大吉,解決了?并不。當切片擴容時,Go 底層會重新申請新的更大空間,存在與原有切片分離的場景。

因此還是要及時將變更的值返回出來,在主流程上統一處理元數據會更好。

總結

在今天這篇文章中,我們開始了 Go 常見編碼錯誤的第一節,共涉及 5 個案例:

  • nil Map。
  • 空指針的引用。
  • 使用對循環迭代器變量的引用。
  • 在循環迭代器變量上使用 goroutine。
  • 數組不會被改變。

這些案例非常常見,在單一代碼上看會比較容易發覺。但一旦混合到應用程序中,在繁雜代碼里就比較難看出來。

祝大家吸完后少踩坑,少出 BUG。

參考

golang/go/wiki/CommonMistakes

24 Common Mistakes in Go (gotchas) And How To Avoid Them

責任編輯:武曉燕 來源: 腦子進煎魚了
相關推薦

2022-10-17 07:40:21

AI項目數據

2011-06-29 09:27:10

2019-10-08 09:00:00

MySQL數據庫

2021-11-10 15:37:49

Go源碼指令

2021-10-28 19:21:56

GolangGo變量

2023-03-13 13:36:00

Go擴容切片

2021-12-16 06:52:33

Ceph分布式對象

2018-07-06 15:00:50

碼農科技開發

2019-09-24 21:00:59

SQL數據庫基礎數據庫

2019-12-30 09:28:53

Kafka集群ZooKeeper

2016-03-28 13:39:58

戴爾

2018-04-08 22:16:21

2021-11-29 09:45:57

枚舉Go代碼

2020-03-23 08:15:43

JavaScriptError對象函數

2011-08-11 16:56:45

數據挖掘

2010-08-17 09:08:16

數據中心錯誤

2016-03-28 13:45:14

硬盤

2021-01-07 05:40:13

BLE模塊Android

2020-10-28 11:20:55

vue項目技

2023-12-07 08:13:58

Java開發
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 精品中文字幕在线观看 | 久久久精品综合 | 在线一区视频 | 国产精品亚洲成在人线 | 日本精品一区二区 | 国产欧美精品区一区二区三区 | 嫩草影院网址 | 欧美成人一区二区三区 | 热re99久久精品国产99热 | 黄色免费网站在线看 | 在线中文视频 | 羞羞羞视频 | 亚洲精品视频在线 | 亚洲综合资源 | 日本三级全黄三级三级三级口周 | 午夜小电影 | 91深夜福利视频 | 在线欧美小视频 | 久久99这里只有精品 | 成人福利网站 | 欧美成人激情 | 91在线视频免费观看 | 成人做爰www免费看视频网站 | 成人永久免费视频 | 国内自拍偷拍 | 国产精品久久久久999 | 狠狠色综合久久丁香婷婷 | 中文字幕1区 | 国产区在线视频 | 在线观看www高清视频 | 黄色大片免费看 | 国产精品无码久久久久 | 亚洲第一女人av | 久久这里只有精品首页 | av中文字幕在线 | 中文字幕视频网 | 国产精品成人一区二区三区 | 日韩免费福利视频 | www.色.com | 四色永久| www.久久精品 |