Golang need to avoid stepping in the pit 50 1

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 listRob 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 in  range 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.

    1. 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.

    2. 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)
          }
      }
      1. 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 doing  m[string(key)] memory allocations
        • Use  for range an iterative string converted to [] byte iterations:for i,v := range []byte(str) {...}

        Fog: refer to the original

 

Guess you like

Origin www.cnblogs.com/yszr/p/11652736.html