50のゴーシェード:トラップ、落とし穴、および一般的な初心者の間違い





Goはシンプルで楽しい言語です。 しかし、他の言語と同様に、そこには落とし穴があります。 そして、それらの多くでは、囲Goは非難されるべきではありません。 他の言語からのプログラマーの到着の自然な結果であるものもあれば、誤解や詳細の欠如により生じるものもあります。 時間を見つけて公式の仕様、wiki、メーリングリスト、ブログの投稿、ソースコードを読むと、落とし穴の多くが明らかになります。 しかし、誰もがそのように始まるわけではなく、それで問題ありません。 Goを初めて使用する場合は、この記事でコードのデバッグに費やす時間を大幅に節約できます。 Go 1.5以下のバージョンを検討します。



内容



レベル:絶対初心者



1. 開始ブレースを別の行に配置することはできません

2. 未使用の変数

3. 未使用のインポート

4. 短い変数宣言は、関数内でのみ使用できます。

5. 短い広告で変数を再宣言する

6. 短い変数宣言を使用してフィールド値を調整することはできません。

7. 変数のランダムな非表示

8. 明示的に型を指定せずにnilを使用して変数を初期化することはできません

9. nilスライス(スライス)とハッシュテーブル(マップ)の使用

10. ハッシュテーブルの容量

11. 行を空にすることはできません

12. 配列を関数に渡す

13. スライスおよび配列の範囲式の予期しない値

14. スライスとアレイ均一性

15. マップに存在しないキーへのアクセス

16. 行の不変性

17. 文字列をバイトスライス(バイトスライス)に変換、またはその逆

18. 文字列とインデックス演算子

19. 文字列-常にUTF-8でエンコードされたテキストではありません

20. 行の長さ

21. 複数行リテラルのスライス/配列/マップにカンマがありません

22. log.Fatalとlog.Panicはログだけではありません

23. 埋め込みデータ構造の非同期操作

24. 範囲式の文字列の反復値

25. for範囲式を使用したハッシュテーブル(マップ)の反復

26. switchステートメントの不適切な動作

27. 増分および減分

28. ビット単位のNOT演算子

29. オペレーターの優先順位の違い

30. エクスポートされていない構造フィールドはエンコードされません

31. アクティブなゴルーチンを使用したアプリケーションの終了

32. バッファリングされていないチャネルに送信される場合、データは受信者の準備が整うとすぐに返されます

33. 閉じたチャンネルに送信するとパニックにつながる

34. 「nil」チャンネルの使用

35. 値によってパラメーターを取るメソッドは、初期値を変更しません



レベル:経験​​豊富な初心者



36. HTTP応答の本文を閉じる

37. HTTP接続を閉じる

38. インターフェイス値へのJSON番号の非整列化

39. 構造体、配列、スライス、マップの比較

40. パニックからの回復

41. 範囲式のスライス、配列、マップインのフィールド値の更新とバインド

42. スライス内の「隠しデータ」

43. スライス内のデータの「破損」

44.非推奨のスライス

45. メソッドと型宣言

46. 切り替えおよび選択のためにコードブロックから抜け出す方法

47.式の反復変数とクロージャー

48. deferブロックの引数の計算(遅延関数呼び出し引数の評価)

49. 呼び出し延期ブロック

50. 型変換エラー

51. ブロックされたゴルーチンとリソースリーク



レベル:上級者



52. 参照によって値を取得するメソッド(ポインターレシーバー)を値インスタンスに適用する

53. ハッシュテーブルの値フィールドの更新

54. nilインターフェイスとnilインターフェイス値

55. スタック変数とヒープ変数

56. GOMAXPROCS、同時実行性および同時実行性

57. 読み取りおよび書き込み操作の順序変更

58. プリエンプティブスケジューリング



1.開始ブレースを別の行に配置することはできません



中括弧を使用する他のほとんどの言語では、配置する場所を選択する必要があります。 Goはルールから外れます。 このため、セミコロンの自動挿入に感謝することができます(次の行を分析せずに、各行の最後にセミコロンが想定されます)。 はい、Goにはセミコロンがあります!



間違った:



package main

import "fmt"

func main()  
{ // ,        
    fmt.Println("hello there!")
}

      
      





:



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

      
      





:



package main

import "fmt"

func main() {  
    fmt.Println("works!")
}

      
      





2.



, . : , . . .



, . - , .



:



package main

var gvar int // not an error

func main() {  
    var one int   // ,  
    two := 2      // ,  
    var three int // ,      3   
    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 main

import "fmt"

func main() {  
    var one int
    _ = one

    two := 2
    fmt.Println(two)

    var three int
    three = 3
    one = three

    var four int
    four = four
}

      
      





: .



3.



- , , , . , «_» . «_» - .



:



package main

import (  
    "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 main

import (  
    _ "fmt"
    "log"
    "time"
)

var _ = log.Println

func main() {  
    _ = time.Now
}

      
      





: . goimports.



4.



:



package main

myvar := 1 // 

func main() {  
}

      
      





:



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

      
      





:



package main

var myvar = 1

func main() {  
}

      
      





5.



, (multi-variable declarations), — . , (shadowed variable).

:



package main

func main() {  
    one := 0
    one := 1 // 
}

      
      





:



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

      
      





:



package main

func main() {  
    one := 0
    one, two := 1,2

    one,two = two,one
}

      
      





6.



:



package main

import (  
  "fmt"
)

type info struct {  
  result int
}

func work() (int,error) {  
    return 13,nil  
  }

func main() {  
  var data info

  data.result, err := work() // 
  fmt.Printf("info: %+v\n",data)
}

      
      





:



prog.go:18: non-name data.result on left side of :=

      
      





Go , : « ». . .



:



package main

import (  
  "fmt"
)

type info struct {  
  result int
}

func work() (int,error) {  
    return 13,nil  
  }

func main() {  
  var data info

  var err error
  data.result, err = work() // ok
  if err != nil {
    fmt.Println(err)
    return
  }

  fmt.Printf("info: %+v\n",data) // : info: {result:13}
}

      
      





7.



( , Go ), . , , .



package main

import "fmt"

func main() {  
    x := 1
    fmt.Println(x)     //  1
    {
        fmt.Println(x) //  1
        x := 2
        fmt.Println(x) //  2
    }
    fmt.Println(x)     //  1 (,    2)
}

      
      





Go-. . vet. . -shadow: go tool vet -shadow your_file.go







8. nil



nil



« » (zero value) , , , - (map), (slices) . , , .



:



package main

func main() {  
    var x = nil // 

    _ = x
}

      
      





:



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

      
      





:



package main

func main() {  
    var x interface{} = nil

    _ = x
}

      
      





9. nil- (slice) - (map)



nil



-, -, runtime panic.



:



package main

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

      
      





:



package main

func main() {  
    var m map[string]int
    m["one"] = 1 // 

}

      
      





10. -



-, cap()



.



:



package main

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

      
      





:



/tmp/sandbox326543983/main.go:5: invalid argument m (type map[string]int) for cap

      
      





11. nil



, nil



-.



:



package main

func main() {  
    var x string = nil // 

    if x == nil { // 
        x = "default"
    }
}

      
      





:



/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 main



func main() {  
    var x string //     "" ( )

    if x == "" {
        x = "default"
    }
}

      
      





12.



/++, — . , . Go , , , . , .



package main

import "fmt"

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] (,     [7 2 3])
}

      
      





, .



package main

import "fmt"

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]
}

      
      





: . , .



package main

import "fmt"

func main() {  
    x := []int{1,2,3}

    func(arr []int) {
        arr[0] = 7
        fmt.Println(arr) //  [7 2 3]
    }(x)

    fmt.Println(x) //  [7 2 3]
}

      
      





13. range



, for-in



foreach



. Go range



, : — (item index), — (item data).



:



package main

import "fmt"

func main() {  
    x := []string{"a","b","c"}

    for v := range x {
        fmt.Println(v) //  0, 1, 2
    }
}

      
      





:



package main

import "fmt"

func main() {  
    x := []string{"a","b","c"}

    for _, v := range x {
        fmt.Println(v) //  a, b, c
    }
}

      
      





14.



, Go ? , . . — , .



, «» , « ».



, , .



«» . , . . , .



package main

func main() {  
    x := 2
    y := 4

    table := make([][]int,x)
    for i:= range table {
        table[i] = make([]int,y)
    }
}

      
      





« » . , «» , (raw data). — . , .



package main

import "fmt"

func main() {  
    h, w := 2, 4

    raw := make([]int,h*w)
    for i := range raw {
        raw[i] = i
    }
    fmt.Println(raw,&raw[4])
    // : [0 1 2 3 4 5 6 7] <ptr_addr_x>

    table := make([][]int,h)
    for i:= range table {
        table[i] = raw[i*w:i*w + w]
    }

    fmt.Println(table,&table[1][0])
    // : [[0 1 2 3] [4 5 6 7]] <ptr_addr_x>
}

      
      





, , , .



15. map



, nil



- ( ). nil



, « » — nil



. . , - (map record), « ». (, , , « » — false). , , — , .



:



package main

import "fmt"

func main() {  
    x := map[string]string{"one":"a","two":"","three":"c"}

    if v := x["two"]; v == "" { // 
        fmt.Println("no entry")
    }
}

      
      





:



package main

import "fmt"

func main() {  
    x := map[string]string{"one":"a","two":"","three":"c"}

    if _,ok := x["two"]; !ok {
        fmt.Println("no entry")
    }
}

      
      





16.



, . — - (byte slices), . - , - .



:



package main

import "fmt"

func main() {  
    x := "text"
    x[0] = 'T'

    fmt.Println(x)
}

      
      





:



/tmp/sandbox305565531/main.go:7: cannot assign to x[0]

      
      





:



package main

import "fmt"

func main() {  
    x := "text"
    xbytes := []byte(x)
    xbytes[0] = 'T'

    fmt.Println(string(xbytes)) //  Text
}

      
      





, , . «» (rune). «» , (grave accent). «» , Go .



17. - (Byte Slices),



- ( ), . (cast operation), , (reslicing), , -.



Go []byte



string



string



[]byte



, ( todo).



, []byte



map[string]: m[string(key)]



.



for range



, []byte: for i,v := range []byte(str) {...}



.



18.



, , (byte value), ( ).



package main

import "fmt"

func main() {  
    x := "text"
    fmt.Println(x[0]) //  116
    fmt.Printf("%T",x[0]) //  uint8
}

      
      





«» ( / Unicode), for range



. unicode/utf8 utf8string (golang.org/x/exp/utf8string). utf8string At()



. (slice of runes).



19. — UTF-8



UTF-8. . , UTF-8, — . .



, ValidString()



unicode/utf8.



package main

import (  
    "fmt"
    "unicode/utf8"
)

func main() {  
    data1 := "ABC"
    fmt.Println(utf8.ValidString(data1)) // : true

    data2 := "A\xfeC"
    fmt.Println(utf8.ValidString(data2)) // : false
}

      
      





20.



, Python :



data = u'♥'  
print(len(data)) # : 1  

      
      





Go, .



package main

import "fmt"

func main() {  
    data := "♥"
    fmt.Println(len(data)) // : 3
}

      
      





len()



, , Unicode- Python.



Go, RuneCountInString()



unicode/utf8.



package main

import (  
    "fmt"
    "unicode/utf8"
)

func main() {  
    data := "♥"
    fmt.Println(utf8.RuneCountInString(data)) // : 1

      
      





RuneCountInString()



, .



package main

import (  
    "fmt"
    "unicode/utf8"
)

func main() {  
    data := "é"
    fmt.Println(len(data))                    // : 3
    fmt.Println(utf8.RuneCountInString(data)) // : 2
}

      
      





21. slice/array/map



:



package main

func main() {  
    x := []int{
    1,
    2 // error
    }
    _ = x
}

      
      





:



/tmp/sandbox367520156/main.go:6: syntax error: need trailing comma before newline in composite literal /tmp/sandbox367520156/main.go:8: non-declaration statement outside function body /tmp/sandbox367520156/main.go:9: syntax error: unexpected }

      
      





:



package main

func main() {  
    x := []int{
    1,
    2,
    }
    x = x

    y := []int{3,4,} //  
    y = y
}

      
      





, .



22. log.Fatal log.Panic



. , Go . Fatal*()



Panic*()



, .



package main

import "log"

func main() {  
    log.Fatalln("Fatal Level: log entry") //     
    log.Println("Normal Level: log entry")
}

      
      





23.



Go (concurrency), (concurrency safe). . , sync, .



24. range



( , range



) — «» ( / Unicode), . «», . , . , norm (golang.org/x/text/unicode/norm).



for range



UTF-8. - , 0xfffd ( Unicode), . ( UTF-8), -.



package main

import "fmt"

func main() {  
    data := "A\xfe\x02\xff\x04"
    for _,v := range data {
        fmt.Printf("%#x ",v)
    }
    // : 0x41 0xfffd 0x2 0xfffd 0x4 ()

    fmt.Println()
    for _,v := range []byte(data) {
        fmt.Printf("%#x ",v)
    }
    // : 0x41 0xfe 0x2 0xff 0x4 ()
}

      
      





25. - (map) for range



, , (, ). - . (runtime) Go , , , (, ) .



package main

import "fmt"

func main() {  
    m := map[string]int{"one":1,"two":2,"three":3,"four":4}
    for k,v := range m {
        fmt.Println(k,v)
    }
}

      
      





Go Playground (https://play.golang.org/), , , .



26. switch



case



switch



(break). : (fall through) case



.



package main

import "fmt"

func main() {  
    isSpace := func(ch byte) bool {
        switch(ch) {
        case ' ': // 
        case '\t':
            return true
        }
        return false
    }

    fmt.Println(isSpace('\t')) //  true ()
    fmt.Println(isSpace(' '))  //  false ()
}

      
      





case fallthrough



. switch



, .



package main

import "fmt"

func main() {  
    isSpace := func(ch byte) bool {
        switch(ch) {
        case ' ', '\t':
            return true
        }
        return false
    }

    fmt.Println(isSpace('\t')) //  true ()
    fmt.Println(isSpace(' '))  //  true ()
}

      
      





27.



. Go . .



:



package main

import "fmt"

func main() {  
    data := []int{1,2,3}
    i := 0
    ++i // error
    fmt.Println(data[i++]) // 
}

      
      





:



/tmp/sandbox101231828/main.go:8: syntax error: unexpected ++ /tmp/sandbox101231828/main.go:9: syntax error: unexpected ++, expecting :

      
      





:



package main

import "fmt"

func main() {  
    data := []int{1,2,3}
    i := 0
    i++
    fmt.Println(data[i])
}

      
      





28. NOT-



~ NOT- (aka , bitwise complement), Go XOR- (^).



:



package main

import "fmt"

func main() {  
    fmt.Println(~2) // 
}

      
      





:



/tmp/sandbox965529189/main.go:6: the bitwise complement operator is ^

      
      





:



package main

import "fmt"

func main() {  
    var d uint8 = 2
    fmt.Printf("%08b\n",^d)
}

      
      





- , ^ Go — XOR-. , NOT- (, NOT 0x02



) XOR- (, 0x02 XOR 0xff



). , ^ NOT-.



Go AND NOT (&^), NOT. AND NOT / A AND (NOT B)



.



package main

import "fmt"

func main() {  
    var a uint8 = 0x82
    var b uint8 = 0x02
    fmt.Printf("%08b [A]\n",a)
    fmt.Printf("%08b [B]\n",b)

    fmt.Printf("%08b (NOT B)\n",^b)
    fmt.Printf("%08b ^ %08b = %08b [B XOR 0xff]\n",b,0xff,b ^ 0xff)

    fmt.Printf("%08b ^ %08b = %08b [A XOR B]\n",a,b,a ^ b)
    fmt.Printf("%08b & %08b = %08b [A AND B]\n",a,b,a & b)
    fmt.Printf("%08b &^%08b = %08b [A 'AND NOT' B]\n",a,b,a &^ b)
    fmt.Printf("%08b&(^%08b)= %08b [A AND (NOT B)]\n",a,b,a & (^b))
}

      
      





29.



« » (bit clear) (&^), Go , . .



package main

import "fmt"

func main() {  
    fmt.Printf("0x2 & 0x2 + 0x4 -> %#x\n",0x2 & 0x2 + 0x4)
    //prints: 0x2 & 0x2 + 0x4 -> 0x6
    //Go:    (0x2 & 0x2) + 0x4
    //C++:    0x2 & (0x2 + 0x4) -> 0x2

    fmt.Printf("0x2 + 0x2 << 0x1 -> %#x\n",0x2 + 0x2 << 0x1)
    //prints: 0x2 + 0x2 << 0x1 -> 0x6
    //Go:     0x2 + (0x2 << 0x1)
    //C++:   (0x2 + 0x2) << 0x1 -> 0x8

    fmt.Printf("0xf | 0x2 ^ 0x2 -> %#x\n",0xf | 0x2 ^ 0x2)
    //prints: 0xf | 0x2 ^ 0x2 -> 0xd
    //Go:    (0xf | 0x2) ^ 0x2
    //C++:    0xf | (0x2 ^ 0x2) -> 0xf
}

      
      





30.



(struct fields), , (JSON, XML, GON . .), .



package main

import (  
    "fmt"
    "encoding/json"
)

type MyData struct {  
    One int
    two string
}

func main() {  
    in := MyData{1,"two"}
    fmt.Printf("%#v\n",in) //  main.MyData{One:1, two:"two"}

    encoded,_ := json.Marshal(in)
    fmt.Println(string(encoded)) //  {"One":1}

    var out MyData
    json.Unmarshal(encoded,&out)

    fmt.Printf("%#v\n",out) //  main.MyData{One:1, two:""}
}

      
      





31.



. . - — .



package main

import (  
    "fmt"
    "time"
)

func main() {  
    workerCount := 2

    for i := 0; i < workerCount; i++ {
        go doit(i)
    }
    time.Sleep(1 * time.Second)
    fmt.Println("all done!")
}

func doit(workerId int) {  
    fmt.Printf("[%v] is running\n",workerId)
    time.Sleep(3 * time.Second)
    fmt.Printf("[%v] is done\n",workerId)
}

      
      





:



[0] is running 
[1] is running 
all done!

      
      





WaitGroup



. . , - , . kill



. , : .



package main

import (  
    "fmt"
    "sync"
)

func main() {  
    var wg sync.WaitGroup
    done := make(chan struct{})
    workerCount := 2

    for i := 0; i < workerCount; i++ {
        wg.Add(1)
        go doit(i,done,wg)
    }

    close(done)
    wg.Wait()
    fmt.Println("all done!")
}

func doit(workerId int,done <-chan struct{},wg sync.WaitGroup) {  
    fmt.Printf("[%v] is running\n",workerId)
    defer wg.Done()
    <- done
    fmt.Printf("[%v] is done\n",workerId)
}

      
      





, :



[0] is running 
[0] is done 
[1] is running 
[1] is done

      
      





, . ! :



fatal error: all goroutines are asleep - deadlock!

      
      





! ? ? wg.Done()



. .



, WaitGroup



. wg.Done()



, WaitGroup



.



package main

import (  
    "fmt"
    "sync"
)

func main() {  
    var wg sync.WaitGroup
    done := make(chan struct{})
    wq := make(chan interface{})
    workerCount := 2

    for i := 0; i < workerCount; i++ {
        wg.Add(1)
        go doit(i,wq,done,&wg)
    }

    for i := 0; i < workerCount; i++ {
        wq <- i
    }

    close(done)
    wg.Wait()
    fmt.Println("all done!")
}

func doit(workerId int, wq <-chan interface{},done <-chan struct{},wg *sync.WaitGroup) {  
    fmt.Printf("[%v] is running\n",workerId)
    defer wg.Done()
    for {
        select {
        case m := <- wq:
            fmt.Printf("[%v] m => %v\n",workerId,m)
        case <- done:
            fmt.Printf("[%v] is done\n",workerId)
            return
        }
    }
}

      
      





.



32.



, . , , , .



package main

import "fmt"

func main() {  
    ch := make(chan string)

    go func() {
        for m := range ch {
            fmt.Println("processed:",m)
        }
    }()

    ch <- "cmd.1"
    ch <- "cmd.2" //   
}

      
      





33. panic



. ok



(receive statement) false



, , . , , , ok



false



.



panic. , , , .



package main

import (  
    "fmt"
    "time"
)

func main() {  
    ch := make(chan int)
    for i := 0; i < 3; i++ {
        go func(idx int) {
            ch <- (idx + 1) * 2
        }(i)
    }

    // get the first result
    fmt.Println(<-ch)
    close(ch) // (      )
    // do other work
    time.Sleep(2 * time.Second)
}

      
      





. — , . , .



, (special cancellation channel) , .



package main

import (  
    "fmt"
    "time"
)

func main() {  
    ch := make(chan int)
    done := make(chan struct{})
    for i := 0; i < 3; i++ {
        go func(idx int) {
            select {
            case ch <- (idx + 1) * 2: fmt.Println(idx,"sent result")
            case <- done: fmt.Println(idx,"exiting")
            }
        }(i)
    }

    // get first result
    fmt.Println("result:",<-ch)
    close(done)
    // do other work
    time.Sleep(3 * time.Second)
}

      
      





34. «nil»-



nil



. , .



package main

import (  
    "fmt"
    "time"
)

func main() {  
    var ch chan int
    for i := 0; i < 3; i++ {
        go func(idx int) {
            ch <- (idx + 1) * 2
        }(i)
    }

    // get first result
    fmt.Println("result:",<-ch)
    // do other work
    time.Sleep(2 * time.Second)
}

      
      





runtime fatal error: all goroutines are asleep - deadlock!







case



select



.



package main

import "fmt"  
import "time"

func main() {  
    inch := make(chan int)
    outch := make(chan int)

    go func() {
        var in <- chan int = inch
        var out chan <- int
        var val int
        for {
            select {
            case out <- val:
                out = nil
                in = inch
            case val = <- in:
                out = outch
                in = nil
            }
        }
    }()

    go func() {
        for r := range outch {
            fmt.Println("result:",r)
        }
    }()

    time.Sleep(0)
    inch <- 1
    inch <- 2
    time.Sleep(3 * time.Second)
}

      
      





35. , ,



— . , / (receiver argument). , — - (map) — .



package main

import "fmt"

type data struct {  
    num int
    key *string
    items map[string]bool
}

func (this *data) pmethod() {  
    this.num = 7
}

func (this data) vmethod() {  
    this.num = 8
    *this.key = "v.key"
    this.items["vmethod"] = true
}

func main() {  
    key := "key.1"
    d := data{1,&key,make(map[string]bool)}

    fmt.Printf("num=%v key=%v items=%v\n",d.num,*d.key,d.items)
    // prints num=1 key=key.1 items=map[]

    d.pmethod()
    fmt.Printf("num=%v key=%v items=%v\n",d.num,*d.key,d.items)
    // prints num=7 key=key.1 items=map[]

    d.vmethod()
    fmt.Printf("num=%v key=%v items=%v\n",d.num,*d.key,d.items)
    // prints num=7 key=v.key items=map[vmethod:true]
}

      
      





36. HTTP-



HTTP-, HTTP-. , . : . , .



, .



package main

import (  
    "fmt"
    "net/http"
    "io/ioutil"
)

func main() {  
    resp, err := http.Get("https://api.ipify.org?format=json")
    defer resp.Body.Close()// 
    if err != nil {
        fmt.Println(err)
        return
    }

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println(err)
        return
    }

    fmt.Println(string(body))
}

      
      





HTTP-, resp



nil



, runtime panic.



defer



HTTP-.



package main

import (  
    "fmt"
    "net/http"
    "io/ioutil"
)

func main() {  
    resp, err := http.Get("https://api.ipify.org?format=json")
    if err != nil {
        fmt.Println(err)
        return
    }

    defer resp.Body.Close()// ,    :-)
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println(err)
        return
    }

    fmt.Println(string(body))
}

      
      





, HTTP-, resp



nil



, err — non-nil



. non-nil



. .



, non-nil



HTTP-. : defer



.



package main

import (  
    "fmt"
    "net/http"
    "io/ioutil"
)

func main() {  
    resp, err := http.Get("https://api.ipify.org?format=json")
    if resp != nil {
        defer resp.Body.Close()
    }

    if err != nil {
        fmt.Println(err)
        return
    }

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println(err)
        return
    }

    fmt.Println(string(body))
}

      
      





resp.Body.Close()



. HTTP- , keep alive



. HTTP- . . , HTTP- . , Go 1.5.



HTTP-, - :



_, err = io.Copy(ioutil.Discard, resp.Body)

      
      





, , JSON API :



json.NewDecoder(resp.Body).Decode(&data)

      
      





37. HTTP-



HTTP- - ( HTTP 1.1 keep alive



). HTTP- , HTTP-. / .



, true



Close



.



: Connection



close



. HTTP- Connection: close



. , .



package main

import (  
    "fmt"
    "net/http"
    "io/ioutil"
)

func main() {  
    req, err := http.NewRequest("GET","http://golang.org",nil)
    if err != nil {
        fmt.Println(err)
        return
    }

    req.Close = true
    //or do this:
    //req.Header.Add("Connection", "close")

    resp, err := http.DefaultClient.Do(req)
    if resp != nil {
        defer resp.Body.Close()
    }

    if err != nil {
        fmt.Println(err)
        return
    }

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println(err)
        return
    }

    fmt.Println(len(string(body)))
}

      
      





HTTP-. HTTP-.



package main

import (  
    "fmt"
    "net/http"
    "io/ioutil"
)

func main() {  
    tr := &http.Transport{DisableKeepAlives: true}
    client := &http.Client{Transport: tr}

    resp, err := client.Get("http://golang.org")
    if resp != nil {
        defer resp.Body.Close()
    }

    if err != nil {
        fmt.Println(err)
        return
    }

    fmt.Println(resp.StatusCode)

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println(err)
        return
    }

    fmt.Println(len(string(body)))
}

      
      





, . - , . . — .



38. (unmarshalling) JSON-



/ JSON- , Go JSON float64



. , panic:



package main

import (  
  "encoding/json"
  "fmt"
)

func main() {  
  var data = []byte(`{"status": 200}`)

  var result map[string]interface{}
  if err := json.Unmarshal(data, &result); err != nil {
    fmt.Println("error:", err)
    return
  }

  var status = result["status"].(int) // 
  fmt.Println("status value:",status)
}

      
      





Runtime Panic:



panic: interface conversion: interface is float64, not int







JSON-, , , .





39. struct, array, slice map



==



, .



package main

import "fmt"

type data struct {  
    num int
    fp float32
    complex complex64
    str string
    char rune
    yes bool
    events <-chan string
    handler interface{}
    ref *byte
    raw [10]byte
}

func main() {  
    v1 := data{}
    v2 := data{}
    fmt.Println("v1 == v2:",v1 == v2) // : v1 == v2: true
}

      
      





, . , , .



package main

import "fmt"

type data struct {  
    num int                // ok
    checks [10]func() bool // 
    doit func() bool       // 
    m map[string] string   // 
    bytes []byte           // 
}

func main() {  
    v1 := data{}
    v2 := data{}
    fmt.Println("v1 == v2:",v1 == v2)
}

      
      





Go , .



: DeepEqual()



reflect.



package main

import (  
    "fmt"
    "reflect"
)

type data struct {  
    num int                // ok
    checks [10]func() bool // 
    doit func() bool       // 
    m map[string] string   // 
    bytes []byte           // 
}

func main() {  
    v1 := data{}
    v2 := data{}
    fmt.Println("v1 == v2:",reflect.DeepEqual(v1,v2)) // prints: v1 == v2: true

    m1 := map[string]string{"one": "a","two": "b"}
    m2 := map[string]string{"two": "b", "one": "a"}
    fmt.Println("m1 == m2:",reflect.DeepEqual(m1, m2)) // prints: m1 == m2: true

    s1 := []int{1, 2, 3}
    s2 := []int{1, 2, 3}
    fmt.Println("s1 == s2:",reflect.DeepEqual(s1, s2)) // prints: s1 == s2: true
}

      
      





( ), DeepEqual()



.



package main

import (  
    "fmt"
    "reflect"
)

func main() {  
    var b1 []byte = nil
    b2 := []byte{}
    fmt.Println("b1 == b2:",reflect.DeepEqual(b1, b2)) // prints: b1 == b2: false
}

      
      





DeepEqual()



nil



-. , bytes.Equal()



: nil



.



package main

import (  
    "fmt"
    "bytes"
)

func main() {  
    var b1 []byte = nil
    b2 := []byte{}
    fmt.Println("b1 == b2:",bytes.Equal(b1, b2)) // prints: b1 == b2: true
}

      
      





DeepEqual()



.



package main

import (  
    "fmt"
    "reflect"
    "encoding/json"
)

func main() {  
    var str string = "one"
    var in interface{} = "one"
    fmt.Println("str == in:",str == in,reflect.DeepEqual(str, in))
    //prints: str == in: true true

    v1 := []string{"one","two"}
    v2 := []interface{}{"one","two"}
    fmt.Println("v1 == v2:",reflect.DeepEqual(v1, v2))
    //prints: v1 == v2: false (not ok)

    data := map[string]interface{}{
        "code": 200,
        "value": []string{"one","two"},
    }
    encoded, _ := json.Marshal(data)
    var decoded map[string]interface{}
    json.Unmarshal(encoded, &decoded)
    fmt.Println("data == decoded:",reflect.DeepEqual(data, decoded))
    //prints: data == decoded: false (not ok)
}

      
      





- ( ) , , , ToUpper()



ToLower()



bytes strings ( ==



, bytes.Equal()



bytes.Compare()



). , . strings.EqualFold()



bytes.EqualFold()



.



- ( , . .), , reflect.DeepEqual()



, bytes.Equal()



bytes.Compare()



. . , crypto/subtle (, subtle.ConstantTimeCompare()



).



40. panic



recover()



/ panic. , defer.



:



package main

import "fmt"

func main() {  
    recover() //   
    panic("not good")
    recover() //    :)
    fmt.Println("ok")
}

      
      





:



package main

import "fmt"

func main() {  
    defer func() {
        fmt.Println("recovered:",recover())
    }()

    panic("not good")
}

      
      





recover()



, defer.



:



package main

import "fmt"

func doRecover() {  
    fmt.Println("recovered =>",recover()) // prints: recovered => <nil>
}

func main() {  
    defer func() {
        doRecover() //  panic  
    }()

    panic("not good")
}

      
      





41. slice, array map for range



range



— , . , . , , .



package main

import "fmt"

func main() {  
    data := []int{1,2,3}
    for _,v := range data {
        v *= 10 //   
    }

    fmt.Println("data:",data) // : [1 2 3]
}

      
      





, .



package main

import "fmt"

func main() {  
    data := []int{1,2,3}
    for i,_ := range data {
        data[i] *= 10
    }

    fmt.Println("data:",data) // : [10 20 30]
}

      
      





, . , . , , for range



.



package main

import "fmt"

func main() {  
    data := []*struct{num int} {{1},{2},{3}}

    for _,v := range data {
        v.num *= 10
    }

    fmt.Println(data[0],data[1],data[2]) // prints &{10} &{20} &{30}
}

      
      





42. « »



. . , , .



package main

import "fmt"

func get() []byte {  
    raw := make([]byte,10000)
    fmt.Println(len(raw),cap(raw),&raw[0]) // : 10000 10000 <byte_addr_x>
    return raw[:3]
}

func main() {  
    data := get()
    fmt.Println(len(data),cap(data),&data[0]) // : 3 10000 <byte_addr_x>
}

      
      





, , ( ).



package main

import "fmt"

func get() []byte {  
    raw := make([]byte,10000)
    fmt.Println(len(raw),cap(raw),&raw[0]) // : 10000 10000 <byte_addr_x>
    res := make([]byte,3)
    copy(res,raw[:3])
    return res
}

func main() {  
    data := get()
    fmt.Println(len(data),cap(data),&data[0]) // : 3 3 <byte_addr_y>
}

      
      





43. «»



, ( ). , , , .



package main

import (  
    "fmt"
    "bytes"
)

func main() {  
    path := []byte("AAAA/BBBBBBBBB")
    sepIndex := bytes.IndexByte(path,'/')
    dir1 := path[:sepIndex]
    dir2 := path[sepIndex+1:]
    fmt.Println("dir1 =>",string(dir1)) // : dir1 => AAAA
    fmt.Println("dir2 =>",string(dir2)) // : dir2 => BBBBBBBBB

    dir1 = append(dir1,"suffix"...)
    path = bytes.Join([][]byte{dir1,dir2},[]byte{'/'})

    fmt.Println("dir1 =>",string(dir1)) // : dir1 => AAAAsuffix
    fmt.Println("dir2 =>",string(dir2)) // : dir2 => uffixBBBB (not ok)

    fmt.Println("new path =>",string(path))
}

      
      





. AAAAsuffix/BBBBBBBBB AAAAsuffix/uffixBBBB. , . . .



, . : (full slice expression).



package main

import (  
    "fmt"
    "bytes"
)

func main() {  
    path := []byte("AAAA/BBBBBBBBB")
    sepIndex := bytes.IndexByte(path,'/')
    dir1 := path[:sepIndex:sepIndex] //   
    dir2 := path[sepIndex+1:]
    fmt.Println("dir1 =>",string(dir1)) // : dir1 => AAAA
    fmt.Println("dir2 =>",string(dir2)) // : dir2 => BBBBBBBBB

    dir1 = append(dir1,"suffix"...)
    path = bytes.Join([][]byte{dir1,dir2},[]byte{'/'})

    fmt.Println("dir1 =>",string(dir1)) // : dir1 => AAAAsuffix
    fmt.Println("dir2 =>",string(dir2)) // : dir2 => BBBBBBBBB (ok now)

    fmt.Println("new path =>",string(path))
}

      
      





. .



44. «»



. , . , «» .



- , . ( ) .



import "fmt"

func main() {  
    s1 := []int{1,2,3}
    fmt.Println(len(s1),cap(s1),s1) //  3 3 [1 2 3]

    s2 := s1[1:]
    fmt.Println(len(s2),cap(s2),s2) //  2 2 [2 3]

    for i := range s2 { s2[i] += 20 }

    //       
    fmt.Println(s1) //  [1 22 23]
    fmt.Println(s2) //  [22 23]

    s2 = append(s2,4)

    for i := range s2 { s2[i] += 10 }

    //s1 is now "stale"
    fmt.Println(s1) //  [1 22 23]
    fmt.Println(s2) //  [32 33 14]
}

      
      





45.



( ), , .



:



package main

import "sync"

type myMutex sync.Mutex

func main() {  
    var mtx myMutex
    mtx.Lock() // 
    mtx.Unlock() // 
}

      
      





:



/tmp/sandbox106401185/main.go:9: mtx.Lock undefined (type myMutex has no field or method Lock) /tmp/sandbox106401185/main.go:10: mtx.Unlock undefined (type myMutex has no field or method Unlock)

      
      





, , .



:



package main

import "sync"

type myLocker struct {  
    sync.Mutex
}

func main() {  
    var lock myLocker
    lock.Lock() // ok
    lock.Unlock() // ok
}

      
      





.



:



package main

import "sync"

type myLocker sync.Locker

func main() {  
    var lock myLocker = new(sync.Mutex)
    lock.Lock() // ok
    lock.Unlock() // ok
}

      
      





46. for switch for select





break



(label) switch/select



. return



— , — .



package main

import "fmt"

func main() {  
    loop:
        for {
            switch {
            case true:
                fmt.Println("breaking out...")
                break loop
            }
        }

    fmt.Println("out!")
}

      
      





goto







47. for



Go. for



. , (aka ), for



, ( , ).



:



package main

import (  
    "fmt"
    "time"
)

func main() {  
    data := []string{"one","two","three"}

    for _,v := range data {
        go func() {
            fmt.Println(v)
        }()
    }

    time.Sleep(3 * time.Second)
    //  : three, three, three
}

      
      





( ): for



.



:



package main

import (  
    "fmt"
    "time"
)

func main() {  
    data := []string{"one","two","three"}

    for _,v := range data {
        vcopy := v //
        go func() {
            fmt.Println(vcopy)
        }()
    }

    time.Sleep(3 * time.Second)
    //  : one, two, three
}

      
      





: .



:



package main

import (  
    "fmt"
    "time"
)

func main() {  
    data := []string{"one","two","three"}

    for _,v := range data {
        go func(in string) {
            fmt.Println(in)
        }(v)
    }

    time.Sleep(3 * time.Second)
    //  : one, two, three
}

      
      





.



:



package main

import (  
    "fmt"
    "time"
)

type field struct {  
    name string
}

func (p *field) print() {  
    fmt.Println(p.name)
}

func main() {  
    data := []field{{"one"},{"two"},{"three"}}

    for _,v := range data {
        go v.print()
    }

    time.Sleep(3 * time.Second)
    //  : three, three, three
}

      
      





:



package main

import (  
    "fmt"
    "time"
)

type field struct {  
    name string
}

func (p *field) print() {  
    fmt.Println(p.name)
}

func main() {  
    data := []field{{"one"},{"two"},{"three"}}

    for _,v := range data {
        v := v
        go v.print()
    }

    time.Sleep(3 * time.Second)
    //  : one, two, three
}

      
      





, ( ), ?



package main

import (  
    "fmt"
    "time"
)

type field struct {  
    name string
}

func (p *field) print() {  
    fmt.Println(p.name)
}

func main() {  
    data := []*field{{"one"},{"two"},{"three"}}

    for _,v := range data {
        go v.print()
    }

    time.Sleep(3 * time.Second)
}

      
      





48. defer (Deferred Function Call Argument Evaluation)



, defer



( ).



package main

import "fmt"

func main() {  
    var i int = 1

    defer fmt.Println("result =>",func() int { return i * 2 }())
    i++
    //: result => 2 (not ok if you expected 4)
}

      
      





49. defer



, . , . , for



, (defer



) .



package main

import (  
    "fmt"
    "os"
    "path/filepath"
)

func main() {  
    if len(os.Args) != 2 {
        os.Exit(-1)
    }

    start, err := os.Stat(os.Args[1])
    if err != nil || !start.IsDir(){
        os.Exit(-1)
    }

    var targets []string
    filepath.Walk(os.Args[1], func(fpath string, fi os.FileInfo, err error) error {
        if err != nil {
            return err
        }

        if !fi.Mode().IsRegular() {
            return nil
        }

        targets = append(targets,fpath)
        return nil
    })

    for _,target := range targets {
        f, err := os.Open(target)
        if err != nil {
            fmt.Println("bad target:",target,"error:",err) // : too many open files
            break
        }
        defer f.Close() //       
        //  -  ...
    }
}

      
      





— .



package main

import (  
    "fmt"
    "os"
    "path/filepath"
)

func main() {  
    if len(os.Args) != 2 {
        os.Exit(-1)
    }

    start, err := os.Stat(os.Args[1])
    if err != nil || !start.IsDir(){
        os.Exit(-1)
    }

    var targets []string
    filepath.Walk(os.Args[1], func(fpath string, fi os.FileInfo, err error) error {
        if err != nil {
            return err
        }

        if !fi.Mode().IsRegular() {
            return nil
        }

        targets = append(targets,fpath)
        return nil
    })

    for _,target := range targets {
        func() {
            f, err := os.Open(target)
            if err != nil {
                fmt.Println("bad target:",target,"error:",err)
                return
            }
            defer f.Close() // ok
            //  -  ...
        }()
    }
}

      
      





: defer



:-)



50.



« » , . , .



:



package main

import "fmt"

func main() {  
    var data interface{} = "great"

    if data, ok := data.(int); ok {
        fmt.Println("[is an int] value =>",data)
    } else {
        fmt.Println("[not an int] value =>",data)
        //: [not an int] value => 0 (not "great")
    }
}

      
      





:



package main

import "fmt"

func main() {  
    var data interface{} = "great"

    if res, ok := data.(int); ok {
        fmt.Println("[is an int] value =>",res)
    } else {
        fmt.Println("[not an int] value =>",data)
        // : [not an int] value => great (as expected)
    }
}

      
      





51.



«Go Concurrency Patterns» Google I/O 2012- concurrency-. — .



func First(query string, replicas ...Search) Result {  
    c := make(chan Result)
    searchReplica := func(i int) { c <- replicas[i](query) }
    for i := range replicas {
        go searchReplica(i)
    }
    return <-c
}

      
      





(replica) . . .



? ?



First()



. , . . , (replica), .



, (exit). : , .



func First(query string, replicas ...Search) Result {  
    c := make(chan Result,len(replicas))
    searchReplica := func(i int) { c <- replicas[i](query) }
    for i := range replicas {
        go searchReplica(i)
    }
    return <-c
}

      
      





: select



(case) default



. default



, , .



func First(query string, replicas ...Search) Result {  
    c := make(chan Result,1)
    searchReplica := func(i int) {
        select {
        case c <- replicas[i](query):
        default:
        }
    }
    for i := range replicas {
        go searchReplica(i)
    }
    return <-c
}

      
      





(special cancellation channel) .



func First(query string, replicas ...Search) Result {  
    c := make(chan Result)
    done := make(chan struct{})
    defer close(done)
    searchReplica := func(i int) {
        select {
        case c <- replicas[i](query):
        case <- done:
        }
    }
    for i := range replicas {
        go searchReplica(i)
    }

    return <-c
}

      
      





? (slides) . , , , .



52. , (pointer receiver),



(addressable), , . , , .



. - (map) . , , .



package main

import "fmt"

type data struct {  
    name string
}

func (p *data) print() {  
    fmt.Println("name:",p.name)
}

type printer interface {  
    print()
}

func main() {  
    d1 := data{"one"}
    d1.print() //ok

    var in printer = data{"two"} // 
    in.print()

    m := map[string]data {"x":data{"three"}}
    m["x"].print() //
}

      
      





:



/tmp/sandbox017696142/main.go:21: cannot use data literal (type data) as type printer in assignment: data does not implement printer (print method has pointer receiver)
/tmp/sandbox017696142/main.go:25: cannot call pointer method on m["x"] /tmp/sandbox017696142/main.go:25: cannot take the address of m["x"]

      
      





53. -



, , .



:



package main

type data struct {  
    name string
}

func main() {  
    m := map[string]data {"x":{"one"}}
    m["x"].name = "two" // error
}

      
      





:



/tmp/sandbox380452744/main.go:9: cannot assign to m["x"].name

      
      





, .



, — .



package main

import "fmt"

type data struct {  
    name string
}

func main() {  
    s := []data {{"one"}}
    s[0].name = "two" // ok
    fmt.Println(s)    // prints: [{two}]
}

      
      





, - (gccgo) . :-) , Go 1.3. , todo.



: .



package main
import "fmt"

type data struct {  
    name string
}

func main() {  
    m := map[string]data {"x":{"one"}}
    r := m["x"]
    r.name = "two"
    m["x"] = r
    fmt.Printf("%v",m) //: map[x:{two}]
}

      
      





: - .



package main

import "fmt"

type data struct {  
    name string
}

func main() {  
    m := map[string]*data {"x":{"one"}}
    m["x"].name = "two" //ok
    fmt.Println(m["x"]) //: &{two}
}

      
      





, , ?



package main

type data struct {  
    name string
}

func main() {  
    m := map[string]*data {"x":{"one"}}
    m["z"].name = "what?" //???
}

      
      





54. nil- nil-



Go. — , . nil



, nil



.



, . , nil



, .



package main

import "fmt"

func main() {  
    var data *byte
    var in interface{}

    fmt.Println(data,data == nil) // : <nil> true
    fmt.Println(in,in == nil)     // : <nil> true

    in = data
    fmt.Println(in,in == nil)     // : <nil> false
    //'data'  'nil',  'in' —  'nil'
}

      
      





, , .



:



package main

import "fmt"

func main() {  
    doit := func(arg int) interface{} {
        var result *struct{} = nil

        if(arg > 0) {
            result = &struct{}{}
        }

        return result
    }

    if res := doit(-1); res != nil {
        fmt.Println("good result:",res) // : good result: <nil>
        // 'res'   'nil',    — 'nil'
    }
}

      
      





:



package main

import "fmt"

func main() {  
    doit := func(arg int) interface{} {
        var result *struct{} = nil

        if(arg > 0) {
            result = &struct{}{}
        } else {
            return nil //   'nil'
        }

        return result
    }

    if res := doit(-1); res != nil {
        fmt.Println("good result:",res)
    } else {
        fmt.Println("bad result (res is nil)") //  —   
    }
}

      
      





55.



, . ++ new



, . Go , new()



make()



. « » (escape analysis). , , , ++.



, , -gcflags -m



go build



go run



(, go run -gcflags -m app.go



).



56. GOMAXPROCS, (concurrency)



Go 1.4 / . , . Go 1.5 , runtime.NumCPU()



. , CPU . , GOMAXPROCS



runtime.GOMAXPROCS()



.



, GOMAXPROCS



, Go . runtime.GOMAXPROCS()



. GOMAXPROCS



(https://golang.org/pkg/runtime/) .



GOMAXPROCS



, — 256.



package main

import (  
    "fmt"
    "runtime"
)

func main() {  
    fmt.Println(runtime.GOMAXPROCS(-1)) // : X (1 on play.golang.org)
    fmt.Println(runtime.NumCPU())       // : X (1 on play.golang.org)
    runtime.GOMAXPROCS(20)
    fmt.Println(runtime.GOMAXPROCS(-1)) // : 20
    runtime.GOMAXPROCS(300)
    fmt.Println(runtime.GOMAXPROCS(-1)) // : 256
}

      
      





57.



Go , , , . .



package main

import (  
    "runtime"
    "time"
)

var _ = runtime.GOMAXPROCS(3)

var a, b int

func u1() {  
    a = 1
    b = 2
}

func u2() {  
    a = 3
    b = 4
}

func p() {  
    println(a)
    println(b)
}

func main() {  
    go u1()
    go u2()
    go p()
    time.Sleep(1 * time.Second)
}

      
      





, a



b



:



1 
2

3 
4

0 
2

0 
0

1 
4

      
      





— 02 — , b



a



.



, sync.



58. (Preemptive Scheduling)



(rogue) , . , for



, .



package main

import "fmt"

func main() {  
    done := false

    go func(){
        done = true
    }()

    for !done {
    }
    fmt.Println("done!")
}

      
      





for



. , , .



, go



, , . , (non-inlined) .



package main

import "fmt"

func main() {  
    done := false

    go func(){
        done = true
    }()

    for !done {
        fmt.Println("not done!") //  
    }
    fmt.Println("done!")
}

      
      





, , -gcflags –m



go build



go run



(, go build -gcflags -m



).



: . Gosched()



runtime.



package main

import (  
    "fmt"
    "runtime"
)

func main() {  
    done := false

    go func(){
        done = true
    }()

    for !done {
        runtime.Gosched()
    }
    fmt.Println("done!")
}

      
      





, Reddit ( , . — . .).



All Articles