This is a creation in Article, where the information may have evolved or changed.
This article translates many of the English documents that have been shared by various Go language communities in the recent past, shades of go:traps, gotchas, and Common mistakes for New Golang Devs, small series first eye thought of the shades of Grey .....
The go language is a simple but profound language. However, even if it is the simplest C language, can be summed up a "C traps and defects", not to mention the go language. Many of the pits in the go language are not really the problem of go itself. Some mistakes you can make in other languages, such as scopes, some errors are caused by the features of the Go language that are not understood, such as range.
In fact, if you are learning the go language carefully to read official documents, Wikipedia, mailing lists or other celebrity blogs like Rob Pike, reports, then many of the pits mentioned in this article can be avoided. But not everyone will learn from the basics, for example, translators like to simply and rudely write programs directly in the Go language. If you are like a translator, then you should read this article: This avoids wasting too much time in debugging programs.
This article divides 50 pits into the following three levels in terms of usage and ease of use: "Beginner entry Level", "Beginner Level", "Beginner into Class".
"{" cannot be placed on one line alone
Level: Beginner Entry level
The Go language designer certainly has a dubious relationship with the C language designer (K&r), because the K&r format in the C language is carried forward in the go language. In most languages, the opening parenthesis in curly braces can be placed casually: the C language must be formatted in the K&R format, and the opening parenthesis will be placed at the end of the previous line. But in the go language, the opening parenthesis must be forced to be placed on a single line. This rule is due to "automatic semicolon injection" (automatic semicolon injection).
Add: Go provides a gofmt tool specifically for formatting code.
Error code:
package mainimport "fmt"func main() { //error, can't have the opening brace on a separate line fmt.Println("hello there!")}
Error message:
/tmp/sandbox826898458/main.go:6: syntax error: unexpected semicolon or newline before {
Fix code:
package mainimport "fmt"func main() { fmt.Println("works!")}
The defined variable is not used
Level: Beginner Entry level
If there are unused variables in the code, the code is compiled with an error. Go requires that all variables declared in the code need to be used, except, of course, global variables.
The parameters of the function can also be declared and not used.
Calls to undeclared variables can also cause compilation to fail. Like the C language, the Go compiler is also a woman, and you should try to be satisfied with what he says.
Error code:
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?")}
Error message:
/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
Fix code:
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}
Of course, you can also consider deleting variables that are not used.
Unused packages
Level: Beginner Entry level
When you import a package, if you do not use the package, or the function/interface/data structure/variables in the package, it will fail to compile.
If you really confirm that you want to introduce a variable but not use it, we can use the "" identifier to sit on the tag to avoid compilation failure. The "" identifier indicates that these packages are introduced in order to obtain the side effects of these packages.
Error code:
package mainimport ( "fmt" "log" "time")func main() { }
Error message:
/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"
Fix code
package mainimport ( _ "fmt" "log" "time")var _ = log.Printlnfunc main() { _ = time.Now}
You can only use a short variable declaration inside a function
Level: Beginner Entry level
Error code:
package mainmyvar := 1 //errorfunc main() { }
Error message:
/tmp/sandbox265716165/main.go:3: non-declaration statement outside function body
Fix code:
package mainvar myvar = 1func main() { }
The variable cannot be re-assigned using a thin assignment statement
Level: Beginner Entry level
You cannot re-assign a single variable using a thin assignment statement, but you can assign multiple variables at the same time using a thin assignment statement.
Also, the redefined variables must be written in the same block of code.
Error message:
package mainfunc main() { one := 0 one := 1 //error}
Error message:
/tmp/sandbox706333626/main.go:5: no new variables on left side of :=
Fix code:
package mainfunc main() { one := 0 one, two := 1,2 one,two = two,one}
Implicit variables (scope)
Level: Beginner Entry level
Like the C language, the Go language also works, and a variable is scoped to just one block of code. Although a thin assignment statement is simple, note the scope.
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)}
Even for experienced developers, this is a deep hole that will fall in unnoticed.
You cannot use nil to assign a value to a variable unless specifically specified
Level: Beginner Entry level
Nil can be used as a "null" for interface, function, pointer, map, slice, and channel. However, if not specifically specified, the Go language does not recognize the type, so it will error.
Error message:
package mainfunc main() { var x = nil //error _ = x}
Error message:
/tmp/sandbox188239583/main.go:4: use of untyped nil
Fix code:
package mainfunc main() { var x interface{} = nil _ = x}
Nil value of Slice and Map
Level: Beginner Entry level
Slice with an initial value of nil can be "added", but the "add" operation for the MAP will cause a runtime panic. (") panic.
Fix code:
package mainfunc main() { var s []int s = append(s,1)}
Error message:
package mainfunc main() { var m map[string]int m["one"] = 1 //error}
Map fixed length
Level: Beginner Entry level
You can specify the length of the map when you create the map, but you cannot use the CAP () function to re-specify the size of the map at run time, and the map is fixed-length.
Error message:
package mainfunc main() { m := make(map[string]int,99) cap(m) //error}
Error message:
/tmp/sandbox326543983/main.go:5: invalid argument m (type map[string]int) for cap
The string cannot be nil
Level: Beginner Entry level
All developers may step on the pit, in C language is Yes char *String=NULL
, but the Go language can not be assigned to nil.
Error message:
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)
Fix code:
package mainfunc main() { var x string //defaults to "" (zero value) if x == "" { x = "default" }}
The array in the parameter
Array Function Arguments
Level: Beginner Entry level
For C and C + + developers, arrays are pointers. To pass an array to a function is to pass the memory address, the modification of the array is the modification of the original address data. However, in the Go language, the passed array is not a memory address, but a copy of the original array, so it is not possible to pass the array method to modify the original address of the data.
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])}
If you need to modify the data of the original array, you need to use an array pointer (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]}
Or you can use 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]}
Using range of Slice and Array will result in unexpected results
Level: Beginner Entry level
If you are familiar with other languages for in
foreach
, then the range used in Go is completely different. Because the range will return two values each time, the first value is the number in Slice and Array, and the second is the corresponding data.
Error code:
package mainimport "fmt"func main() { x := []string{"a","b","c"} for v := range x { fmt.Println(v) //prints 0, 1, 2 }}
Fix code:
package mainimport "fmt"func main() { x := []string{"a","b","c"} for _, v := range x { fmt.Println(v) //prints a, b, c }}
(") How to have the" great God "this label ...
This sequel will be released before eight o'clock in the evening, so please look forward to it.