
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 ( , . — . .).