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-, , , .
- :-)
- , .
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 = uint64(result["status"].(float64)) // fmt.Println("status value:",status) }
-
Decoder
JSON JSON-Number
.
package main import ( "encoding/json" "bytes" "fmt" ) func main() { var data = []byte(`{"status": 200}`) var result map[string]interface{} var decoder = json.NewDecoder(bytes.NewReader(data)) decoder.UseNumber() if err := decoder.Decode(&result); err != nil { fmt.Println("error:", err) return } var status,_ = result["status"].(json.Number).Int64() // fmt.Println("status value:",status) }
Number
, :
package main import ( "encoding/json" "bytes" "fmt" ) func main() { var data = []byte(`{"status": 200}`) var result map[string]interface{} var decoder = json.NewDecoder(bytes.NewReader(data)) decoder.UseNumber() if err := decoder.Decode(&result); err != nil { fmt.Println("error:", err) return } var status uint64 if err := json.Unmarshal([]byte(result["status"].(json.Number).String()), &status); err != nil { fmt.Println("error:", err) return } fmt.Println("status value:",status) }
-
struct
, (maps) .
package main import ( "encoding/json" "bytes" "fmt" ) func main() { var data = []byte(`{"status": 200}`) var result struct { Status uint64 `json:"status"` } if err := json.NewDecoder(bytes.NewReader(data)).Decode(&result); err != nil { fmt.Println("error:", err) return } fmt.Printf("result => %+v",result) //prints: result => {Status:200} }
-
struct
json.RawMessage
, .
, JSON- (conditional field) .
package main import ( "encoding/json" "bytes" "fmt" ) func main() { records := [][]byte{ []byte(`{"status": 200, "tag":"one"}`), []byte(`{"status":"ok", "tag":"two"}`), } for idx, record := range records { var result struct { StatusCode uint64 StatusName string Status json.RawMessage `json:"status"` Tag string `json:"tag"` } if err := json.NewDecoder(bytes.NewReader(record)).Decode(&result); err != nil { fmt.Println("error:", err) return } var sstatus string if err := json.Unmarshal(result.Status, &sstatus); err == nil { result.StatusName = sstatus } var nstatus uint64 if err := json.Unmarshal(result.Status, &nstatus); err == nil { result.StatusCode = nstatus } fmt.Printf("[%v] result => %+v\n",idx,result) } }
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 ( , . — . .).