記一次golang中的賦值覆蓋錯誤

記一次golang中的賦值覆蓋錯誤

最近在用golang寫一個簡單的小服務的時候發生了個小錯誤,對於golang的作用域和賦值來講比較有典型意義在這裡記錄一下。

寫一個簡單的web服務的時候發現了一個錯誤

![](img.alicdn.com/tfs/TB1p)

可以看到倒數第二行接受請求的時候,發生了個空指針異常 但是我沒有panic 先列印了出來

![](img.alicdn.com/tfs/TB1f)

錯誤是由上面的exec方法引起的,目錄結構是:

![](img.alicdn.com/tfs/TB14)

可以看到把資料庫的連接放到了一個db包里

這是資料庫的db的代碼

![](img.alicdn.com/tfs/TB1u)

可以看到 DB的是內部的引用重新賦值了導致我們引入了一個沒有初始化的*sql.DB 也就是空的指針

解決方法是從新聲明err 用 = 賦值

![](img.alicdn.com/tfs/TB1s)

golang 的 := 集合了聲明變數和類型推導的功能

從這裡可以看出golang對於 := 的賦值雖然有類型推導的優勢但是卻容易導致類似的空指針問題,而解決方法只能顯示的聲明另一個變數然後用 = 賦值 這些問題時常顯得很隱晦,而本質上都是為作用域定義和垃圾回收行方便,就像js中的局部作用域中的var聲明一樣。

golang與rust相比,rust用所有權的方式把堆上的內存指向單個變數在變數退出時就可以的避免二次釋放的問題 從而做到沒有gc,但是這樣rust堆上的內存操作就需要掌握一套所謂的所有權規則來手動進行,比如像這樣是會報錯的s1的所有權已經交出了

```

let s1 = String::from("我是堆上的數據");

let s2 = s1;

println!("{}, 還在嗎?", s1);

```

```

let s2 = s1;

| -- value moved here

4 |

5 | println!("{}, 還在嗎?", s1);

| ^^ value used here after move

```

golang是很少需要關注這個數據到底是在哪裡的,所以golang寫起來更加的友好性能也不差。golang是個很棒的語言,只是你需要適應一下而已。


推薦閱讀:

機器學習與編譯優化的入門介紹
總結篇5 編譯器——Compiler
5分鐘入門CTS-嘗鮮中文版TypeScript
讓 Go 很容易手寫 Parser

TAG:Go語言 | 編程語言 | 編譯器 |