Go 語言從新手到大神:每個人都會踩的五十個坑

來源:互聯網
上載者:User

標籤:mic   sign   comment   空值   error:   invalid   app   括弧   規則   

Go語言是一個簡單卻蘊含深意的語言。但是,即便號稱是最簡單的C語言,都能總結出一本《C陷阱與缺陷》,更何況Go語言呢。Go語言中的許多坑其實並不是因為Go自身的問題。一些錯誤你再別的語言中也會犯,例如範圍,一些錯誤就是對因為 Go 語言的特性不瞭解而導致的,例如 range。

其實如果你在學習Go語言的時候去認真地閱讀官方文檔,百科,郵件清單或者其他的類似 Rob Pike 的名人部落格,報告,那麼本文中提到的許多坑都可以避免。但是不是每個人都會從基礎學起,例如譯者就喜歡簡單粗暴地直接用Go語言寫程式。如果你也像譯者一樣,那麼你應該讀一下這篇文章:這樣可以避免在偵錯工具時浪費過多時間。

本文將50個坑按照使用使用範圍和難易程度分為以下三個層級:“新手入門級”,“新手深入級”,“新手進階級”。

“{”不能單獨放在一行

層級:新手入門級

Go語言設計者肯定和C語言設計者(K&R)有種不明不白的關係,因為C語言中的K&R格式在Go語言中得到發揚光大。大多數語言中,大括弧中的左括弧是可以隨便放在哪裡的:C語言中必須要按照K&R格式對代碼進行格式化之後,左括弧才會被放在前一行中的最後。但是Go語言中,左括弧必須強制不能單獨放在一行。這個規則得益於“自動分號注射”(automatic semicolon injection)。

補充:go提供了專門用于格式化代碼的gofmt工具。

出錯代碼:

package mainimport "fmt"func main()  { //error, can‘t have the opening brace on a separate line    fmt.Println("hello there!")}

錯誤資訊:

/tmp/sandbox826898458/main.go:6: syntax error: unexpected semicolon or newline before {

修正代碼:

package mainimport "fmt"func main() {      fmt.Println("works!")}
未使用已定義的變數

層級:新手入門級

如果代碼中有未使用的變數,那個代碼編譯的時候就會報錯。Go要求在代碼中所有聲明的變數都需要被用到,當然,全域變數除外。函數的參數也可以只被聲明,不被使用。

對於未聲明變數的調用同樣會導致編譯失敗。和C語言一樣,Go編譯器也是個女人,他說什麼你都要儘力滿足。

出錯代碼:

package mainvar gvar int //not an errorfunc main() {      var one int   //error, unused variable    two := 2      //error, unused variable    var three int //error, even though it‘s assigned 3 on the next line    three = 3    func(unused string) {        fmt.Println("Unused arg. No compile error")    }("what?")}

錯誤資訊:

/tmp/sandbox473116179/main.go:6: one declared and not used /tmp/sandbox473116179/main.go:7: two declared and not used /tmp/sandbox473116179/main.go:8: three declared and not used

修正代碼:

package mainimport "fmt"func main() {      var one int    _ = one    two := 2     fmt.Println(two)    var three int     three = 3    one = three    var four int    four = four}

當然,你也可以考慮刪除那些沒有使用的變數。

未使用的包

層級:新手入門級

當import一個包之後,如果不使用這個包,或者這個包中的函數/介面/資料結構/變數,那麼將會編譯失敗。

如果真的確認要引入變數但是不使用的話,我們可以用“”標識符座標記,避免編譯失敗。“”標識符表示為了得到這些包的副作用而引入這些包。

出錯代碼:

package mainimport (      "fmt"    "log"    "time")func main() {  }

錯誤資訊:

/tmp/sandbox627475386/main.go:4: imported and not used: "fmt" /tmp/sandbox627475386/main.go:5: imported and not used: "log" /tmp/sandbox627475386/main.go:6: imported and not used: "time"

修正代碼

package mainimport (      _ "fmt"    "log"    "time")var _ = log.Printlnfunc main() {      _ = time.Now}
只能在函數內部使用簡短的變數聲明

層級:新手入門級 出錯代碼:

package mainmyvar := 1 //errorfunc main() {  }

錯誤資訊:

/tmp/sandbox265716165/main.go:3: non-declaration statement outside function body

修正代碼:

package mainvar myvar = 1func main() {  }
無法使用精簡的指派陳述式對變數重新賦值

層級:新手入門級

不能使用精簡的指派陳述式重新賦值單個變數,但是可以使用精簡的指派陳述式同時賦值多個變數。

並且,重定義的變數必須寫在同一個代碼塊。

錯誤資訊:

package mainfunc main() {      one := 0    one := 1 //error}

錯誤資訊:

/tmp/sandbox706333626/main.go:5: no new variables on left side of :=

修正代碼:

package mainfunc main() {      one := 0    one, two := 1,2    one,two = two,one}
隱式變數(範圍)

層級:新手入門級

和 C 語言一樣,Go 語言也有作用於,一個變數的作用範圍僅僅是一個代碼塊。雖然精簡的指派陳述式很簡單,但是注意範圍。

package mainimport "fmt"func main() {      x := 1    fmt.Println(x)     //列印 1    {        fmt.Println(x) //列印 1        x := 2        fmt.Println(x) //列印 2    }    fmt.Println(x)     //列印 1 ( 不是 2)}

甚至對於有經驗的開發人員來說,這也是個不注意就會掉進去的深坑。

除非特別指定,否則無法使用 nil 對變數賦值

層級:新手入門級

nil 可以用作 interface、function、pointer、map、slice 和 channel 的“空值”。但是如果不特別指定的話,Go 語言不能識別類型,所以會報錯。

錯誤資訊:

package mainfunc main() {      var x = nil //error    _ = x}

錯誤資訊:

/tmp/sandbox188239583/main.go:4: use of untyped nil

修正代碼:

package mainfunc main() {      var x interface{} = nil    _ = x}
Slice 和 Map 的 nil 值

層級:新手入門級

初始值為 nil 的 Slice 是可以進行“添加”操作的,但是對於 Map 的“添加”操作會導致運行時恐慌。( ﹁ ﹁ ) 恐慌。

修正代碼:

package mainfunc main() {      var s []int    s = append(s,1)}

錯誤資訊:

package mainfunc main() {      var m map[string]int    m["one"] = 1 //error}
Map 定長

層級:新手入門級

建立 Map 的時候可以指定 Map 的長度,但是在運行時是無法使用 cap() 功能重新指定 Map 的大小,Map 是定長的。

錯誤資訊:

package mainfunc main() {      m := make(map[string]int,99)    cap(m) //error}

錯誤資訊:

/tmp/sandbox326543983/main.go:5: invalid argument m (type map[string]int) for cap
字串無法為 nil

層級:新手入門級

所有的開發人員都可能踩的坑,在 C 語言中是可以 char *String=NULL,但是 Go 語言中就無法賦值為 nil。

錯誤資訊:

package mainfunc main() {      var x string = nil //error    if x == nil { //error        x = "default"    }}

Compile Errors:

/tmp/sandbox630560459/main.go:4: cannot use nil as type string in assignment /tmp/sandbox630560459/main.go:6: invalid operation: x == nil (mismatched types string and nil)

修正代碼:

package mainfunc main() {      var x string //defaults to "" (zero value)    if x == "" {        x = "default"    }}
參數中的數組

Array Function Arguments

層級:新手入門級 對於 C 和 C++ 開發人員來說,數組就是指標。給函數傳遞數組就是傳遞記憶體位址,對數組的修改就是對原地址資料的修改。但是 Go 語言中,傳遞的數組不是記憶體位址,而是原數組的拷貝,所以是無法通過傳遞數組的方法去修改原地址的資料的。

package mainimport "fmt"func main() {      x := [3]int{1,2,3}    func(arr [3]int) {        arr[0] = 7        fmt.Println(arr) //prints [7 2 3]    }(x)    fmt.Println(x) //prints [1 2 3] (not ok if you need [7 2 3])}

如果需要修改原數組的資料,需要使用數組指標(array pointer)。

package mainimport "fmt"func main() {      x := [3]int{1,2,3}    func(arr *[3]int) {        (*arr)[0] = 7        fmt.Println(arr) //prints &[7 2 3]    }(&x)    fmt.Println(x) //prints [7 2 3]}

或者可以使用 Slice,

package mainimport "fmt"func main() {      x := []int{1,2,3}    func(arr []int) {        arr[0] = 7        fmt.Println(arr) //prints [7 2 3]    }(x)    fmt.Println(x) //prints [7 2 3]}
使用 Slice 和 Array 的 range 會導致預料外的結果

層級:新手入門級

如果你對別的語言中的 for in 和 foreach 熟悉的話,那麼 Go 中的 range 使用方法完全不一樣。因為每次的 range 都會返回兩個值,第一個值是在 Slice 和 Array 中的編號,第二個是對應的資料。

出錯代碼:

package mainimport "fmt"func main() {      x := []string{"a","b","c"}    for v := range x {        fmt.Println(v) //prints 0, 1, 2    }}

修正代碼:

package mainimport "fmt"func main() {      x := []string{"a","b","c"}    for _, v := range x {        fmt.Println(v) //prints a, b, c    }}

Go 語言從新手到大神:每個人都會踩的五十個坑(轉)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.