Recent ready to write something about golang technology Bowen, this is before seen on GitHub golang technical translations, feel useful, give our readers to share with you.
Foreword
Go is a simple and fun programming language, like any other language, when you use will inevitably encounter many pits, but most of them are not Go their own design flaws. If you just go to other languages Go, then this article will likely be stepped pit.
If you take the time to learn the official doc, wiki, discuss mailing list , Rob Pike of numerous articles and Go source code, you will find this article in the pit is very common, novice skip these pits, can reduce a lot of time debugging code.
Primary articles: 1-35
1. Left braces {
generally can not be put on a separate line
In most other languages, {
the position you decide. Go Comparative particular, compliance with the rules of injection semicolon (automatic semicolon injection): The compiler will be added after each line of code tail specific delimiter ;
used to separate multiple statements, for example will )
after a semicolon:
// error example func main () { println("hello world") } // equivalent FUNC main (); // no function body { println("hello world") }
./main.go: missing function body ./main.go: syntax error: unexpected semicolon or newline before {
// Good example func main() { println("hello world") } Note that special cases like the code block: {// semicolon does not follow the rules of injection, it does not automatically points in its rear, this time can wrap func main() { { println("hello world") } }
Test: golang automatically add special separator semicolon
2. unused variables
If there are unused variables in the body of the function code can not be compiled, but without using the global variable declaration is possible.
Even after the variable declaration for the variable assignment, still unable to compile, use it somewhere
// error example var GVAR int // global variable declaration can not use func main() { var one int // error: one declared and not used two := 2 // error: two declared and not used var three int // error: three declared and not used three = 3 } // Good example // comment or may be directly removed unused variable FUNC main () { var One int _ = one two := 2 println(two) var three int one = three var four int four = four }
3. import Unused
If you import a package, but the package variables, functions, interfaces, and a structure are not used, it will fail to compile.
You can use _
the package underscore character as an alias to ignore imported, in order to avoid compilation errors, this will only execute the package init()
// error example import ( "fmt" // imported and not used: "fmt" "log" // imported and not used: "log" "time" // imported and not used: "time" ) func main() { } // Good example // goimports tool can be used to annotate or to remove unused packages import ( _ "fmt" "log" "time" ) func main() { _ = log.Println _ = time.Now }
4. A brief statement of the variables can only be used within the function
// 错误示例 myvar := 1 // syntax error: non-declaration statement outside function body func main() { } // correct exemplary var myVar. 1 = func main() { }
5. Use a brief statement to declare variables repeat
Repeat can not be declared as a separate variable with the brief statement the way, :=
on the left there is at least one new variable allowed only repeat the statement multivariate:
// Error Example func main () { one := 0 one := 1 // error: no new variables on left side of := } // correct exemplary func main () { one : 0 = one , TWO: =. 1, 2 // TWO new variable, allow one to repeat the statement. Such error is often treated with the same name as a variable ERR One, TWO = TWO, One // exchange shorthand values of two variables }
6. You can not use a brief statement to the value of a field
struct variable fields can not be used :=
to assign a variable to use predefined resolve to avoid:
// error example type info struct { result int } func work() (int, error) { return 3, nil } func main() { was data info data.result, err := work() // error: non-name data.result on left side of := fmt.Printf("info: %+v\n", data) } // correct exemplary FUNC main () { var Data info var ERR error // ERR need predeclared Data .Result, ERR = Work () IF ERR! = Nil { fmt.Println(err) return } fmt.Printf("info: %+v\n", data) }
7. accidentally overwrite variables
For developers turn over from dynamic languages, the brief statement is useful, which may lead people to misunderstand :=
is an assignment operator.
If you are in a new block of code like below this misuse :=
, the compiler will not complain, but variables do not work according to your expectations:
func main() { x := 1 println(x) // 1 { the println (x) // . 1 x: = 2 the println (x) // 2 // new scope of the x variable only within block } println(x) // 1 }
This is Go developers often make the mistake, and can not easily be found.
Can be used vet tool to diagnose this variable coverage, Go not cover the default check, add -shadow
options to enable:
> go tool vet -shadow main.go main .go:. 9: Declaration of "X" AT main.go Declaration Shadows:. 5 Note that all variables vet not covered by the report, use Go - Nyet do further testing: > $GOPATH/bin/go-nyet main.go main.go:10:3:Shadowing variable `x`
8. explicit types of variables can not be used to initialize nil
nil
It is interface, function, pointer, map, slice channel type, and default initial values of the variable. But do not specify the type of declaration, the compiler can not infer the specific type of the variable.
// Error Example FUNC main () { var X = nil @ error: use of untyped nil _ = X } // correct exemplary FUNC main () { var X interface {} = nil _ = x }
9. The direct use of the slice is nil, map
Allows you to add elements to a value of nil slice, but added elements of the map is nil will result in run-time panic
// Map Error exemplary FUNC main () { var m Map [ String ] int m["one"] = 1 // error: panic: assignment to entry in nil map // m: = make (map [ string] int) // correct statement of the map, the actual memory allocation } // Slice correct exemplary FUNC main () { var S [] int s = append(s, 1) }
10. map Capacity
Capacity can be specified when creating a variable of type map, but you can not use the same slice as cap()
to detect the size of the allocated space:
// Error Example func main () { m := make(map[string]int, 99) println(cap(m)) // error: invalid argument m1 (type map[string]int) for cap }
11. string type variable value is not nil
For those with a love nil
of people initialization string, this is the pits:
// 错误示例 func main() { var s string = nil // cannot use nil as type string in assignment if s == nil { // invalid operation: s == nil (mismatched types string and nil) s = "default" } } // correct exemplary FUNC main () { var S String // zero value of the empty string String type "" IF S == "" { s = "default" } }
12. Array type value as a parameter
In C / C ++, the array (name) is a pointer. When the array as a parameter passed into the function, corresponding to the reference transfer array memory addresses, change the value of the function within the array.
In Go, the array is the value. As a parameter passed into the function, is the original value of passing copy arrays at this time can not be updated in the internal function of the array is:
// array using a reference value of the copy transfer func main () { x := [3]int{1,2,3} func(arr [3]int) { arr[0] = 7 fmt.Println(arr) // [7 2 3] }(x) FMT .Println (X) // [. 1 2 3] // not you think the [723] }
If you want to change a parameter array:
- Direct transfer type pointer points to the array:
-
// pass-by will modify the original data func main () { x := [3]int{1,2,3} func(arr *[3]int) { (*arr)[0] = 7 fmt.Println(arr) // &[7 2 3] }(&x) fmt.Println(x) // [7 2 3] }
Directly slice: even if the internal function is a value obtained copies of the slice, but will still updated original data slice (bottom array)
-
// modify the underlying array slice to modify the Slice FUNC main () { x := []int{1, 2, 3} func(arr []int) { arr[0] = 7 fmt.Println(x) // [7 2 3] }(x) fmt.Println(x) // [7 2 3] }
13. range confuse traversed array slice and return values
And other programming languages
for-in
,foreach
different traversal statement, Go inrange
when traversing generates two values, the first one is the element index, the second is the value of the element: -
// Error Example func main () { x := []string{"a", "b", "c"} for v := range x { FMT .Println (A) // 1 2 3 } } // correct exemplary func main () { X : = [] String { "A", "B", "C" } for _, V: = Range X { // Use _ discarded index FMT. Println (V) } }
14. slice and array is actually a one-dimensional data
Go seems to support multidimensional array and slice, you can create an array of arrays, slices of sliced, but not really.
Application relies on the dynamic multi-dimensional array value is calculated in terms of performance and complexity, with the effect achieved is not satisfactory Go.
You can use the original one-dimensional array, "independent" slices, "to share the underlying array 'slice to create a dynamic multidimensional arrays.
-
The original one-dimensional array: To do a good job index check, overflow detection, and when Adds bonus time to re-do a full array of memory allocation.
-
The use of "independent" sliced in two steps:
- Create an external slice
-
Internal memory allocation for each slice
Note that the interior of the slice independently, so that any slice by an internal compression will not affect any other slice
-
// used independently to create a slice of 6 [2] [3] of the dynamic multi-dimensional arrays func main () { x : = 2 and : = 4 table := make([][]int, x) for i := range table { table[i] = make([]int, y) } }
- Use "shared underlying array" slice
- Creating a storage container slice of raw data
- Create additional slice
- Cutting raw slice to initialize other slice
-
func main() { h, w := 2, 4 raw := make([]int, h*w) for i := range raw { raw[i] = i } // Initialization original Slice fmt.Println (RAW, & RAW [. 4]) // [0. 1. 5. 4. 3 2. 6. 7] 0xc420012120 Table : = the make ([] [] int, H) for I: = Range Table { // equally spaced cutting raw slice, creating a dynamic multidimensional array table // 0: raw[0*4: 0*4 + 4] // 1: raw[1*4: 1*4 + 4] table[i] = raw[i*w : i*w + w] } fmt.Println(table, &table[1][0]) // [[0 1 2 3] [4 5 6 7]] 0xc420012120 }
More reference on multidimensional arrays
go-how-is-two-dimensional-arrays-memory-representation
what-is-a-concise-way-to-create-a-2d-slice-in-go
15. The access key map that does not exist
And other programming language similar, if access does not exist in the map key is hoping to return to nil, for example in PHP:
-
> php -r '$v = ["x"=>1, "y"=>2]; @var_dump($v["z"]);' NULL
Go will return zero value corresponding to the element data type, such as
nil
,''
,false
and 0, the total value of the operation value is returned, so the value can not be taken out to determine the key is not in the map.Check key if there is direct access to a map, check the return of the second argument can be:
-
// error detection key way func main () { x := map[string]string{"one": "2", "two": "", "three": "3"} if v := x["two"]; v == "" { FMT .Println ( "Key entry two IS NO") // key exists or not two empty string returns } } // correct exemplary func main () { x := map[string]string{"one": "2", "two": "", "three": "3"} if _, ok := x["two"]; !ok { fmt.Println("key two is no entry") } }
16. string type value is constant, unchangeable
Try to use the index to traverse a string to update a string of individual characters, it is not allowed.
Values are read-only type string Slice binary byte, if you really want to modify the character string, into the string [] is modified byte, and then converted to string:
-
// modify the error exemplary string func main () { x := "text" x[0] = "T" // error: cannot assign to x[0] fmt.Println(x) } // modified example func main () { x := "text" xBytes := []byte(x) xBytes [ 0] = 'T' // note that in this case T is rune type X = String (xBytes) fmt.Println(x) // Text }
NOTE: The examples are not to update the upper string of correct posture, as a UTF8 encoded characters may occupy a plurality of bytes, such as characters requires 3-4 bytes of storage, which at this time is updated by one byte wrong.
Update string of correct posture: the string into rune slice (this time a rune may account for multiple byte), a direct update rune characters
-
func main() { x := "text" xRunes := []rune(x) xRunes[0] = '我' x = string(xRunes) fmt .Println (the X-) // I EXT }
17. string conversion between byte slice and
When the string, and converting each byte slice, involved in the transformation is a copy of the original value. This conversion process, and cast the operation of other programming languages are different, but also with the old and the new slice slice share different underlying array.
Go in the string and byte slice interchangeable on optimizing two points, avoiding the extra allocation:
- In the
map[string]
time of the find key, use the corresponding[]byte
, avoid doingm[string(key)]
memory allocations - Use
for range
an iterative string converted to [] byte iterations:for i,v := range []byte(str) {...}
- In the
-