Slide 1

Slide 1 text

初級者向け Goの落とし穴と解説 Go(Un)Conference LT #3, JULY 26 2018 Yoichiro Shimizu freee k.k. @budougumi0617

Slide 2

Slide 2 text

● 清水 陽一郎 @budougumi0617 ● freee 株式会社 ○ Backend / Desktop-App Engineer ○ Go / Ruby on Rails / .NET ● golang.tokyo 運営 ● Blog ○ https://budougumi0617.github.io/ 自己紹介

Slide 3

Slide 3 text

About Gopher SECTION ZERO

Slide 4

Slide 4 text

{ On conppass 00. About gopher

Slide 5

Slide 5 text

● Go Brand Book ○ https://golang.org/s/brandbook Gopher IS NO DEAD 00. About gopher

Slide 6

Slide 6 text

Today’s contents About Gopher 00 How to study Go Traps and explanations Today’s summary 01 02 03

Slide 7

Slide 7 text

How to study Go SECTION ONE

Slide 8

Slide 8 text

{ Goのデザインポリシー Each language feature should be easy to understand. 01. How to study Go

Slide 9

Slide 9 text

How do you studying Go? ● Goは簡単というけれど、どう覚える? ○ Read spec? ○ A Tour of Go? ○ On the job? 01. How to study Go

Slide 10

Slide 10 text

There are many traps ● 基本的な書き方はすぐ理解できる ● とはいえ、 曖昧な理解だとハマることも多い ● 知らないとググれもしない問題 01. How to study Go

Slide 11

Slide 11 text

例:曖昧な理解だとハマること1 package main import "fmt" func add(a []int) { a = append(a, 4) fmt.Printf("%v\n", a) // [1 2 3 4] } func main() { a := []int{1, 2, 3} fmt.Printf("%v\n", a) // [1 2 3] add(a) fmt.Printf("%v\n", a) // [1 2 3] } https://play.golang.org/p/A8fouhhtLQZ 呼び出し先で 引数sliceを appendする 01. How to study Go

Slide 12

Slide 12 text

例:曖昧な理解だとハマること2 package main import ( "fmt" ) func main() { go fmt.Println("go!") } https://play.golang.org/p/PUoHxeT-RJu main goroutineが 先に死んで 何も起きない @GROOVEX_SWのGoクイズより 01. How to study Go

Slide 13

Slide 13 text

What can we do? ● 必要なのは体系的な仕様の学習 ● だけど全部は難しい ● ● 愚者は経験に学び、賢者は歴史に学ぶ 01. How to study Go

Slide 14

Slide 14 text

Today's goal ● 対象:ひと通り仕様を理解している人 ● よくあるハマりポイントを解説 ○ 一度はハマる落とし穴 ○ へぇ!ってなる仕様 ● 「それは知らなかった」という 何かを持って帰ってもらうこと 01. How to study Go

Slide 15

Slide 15 text

{ 引用元 - プログラミング言語Go ● Pros ○ 日本語書籍で一番体系的 ○ 設計思想にも言及している ● Cons ○ ~ Go1.6なので contextなどは未言及 ○ database/sql等も薄い 01. How to study Go

Slide 16

Slide 16 text

Traps and Explanations SECTION TWO

Slide 17

Slide 17 text

Loop with defer package main import ( "fmt" ) func useHeavyResource() { for i := 0; i < 5; i++ { defer func() { fmt.Println("Released") }() // Do something with resource } fmt.Println("Finished") } func main() { useHeavyResource() } https://play.golang.org/p/q_V9E1H5Jhy What output? 02. Traps and explanations

Slide 18

Slide 18 text

P167 5.8 遅延関数呼び出し 遅延された関数はそれを含んで いる関数の最後まで実行されま せんので、ループ内のdefer文は 注意深く確認する必要がありま す。

Slide 19

Slide 19 text

Map package main import ( "fmt" ) type s struct { i int s []string } func main() { m := new(map[s]string) fmt.Printf("%v\n", m) } https://play.golang.org/p/rKforjFi2CW Why error? 02. Traps and explanations

Slide 20

Slide 20 text

P105 4.3 マップ 与えられたキーがマップ内にすで にあるキーと等しいかどうか検査 できるように、キーの型Kは==を 使って比較可能でなければなりま せん。

Slide 21

Slide 21 text

Interface package main import ( "bytes" "io" ) func log(buf io.Writer, s string) { if buf != nil { buf.Write([]byte(s)) } } func main() { var b *bytes.Buffer = nil log(b, "foo") } https://play.golang.org/p/QzK9wJQXwcS Why panic? 02. Traps and explanations

Slide 22

Slide 22 text

P213 7.5 インターフェース値 nilポインタを含む インターフェースはnilではない

Slide 23

Slide 23 text

Captured value package main import ( "fmt" "time" ) func main() { for i := 0; i < 5; i++ { go func() { fmt.Printf("%d", i) }() } time.Sleep(2 * time.Second) } https://play.golang.org/p/24O7H2cQZLf Where is problem? 02. Traps and explanations

Slide 24

Slide 24 text

P160 5.6.1 警告:ループ変数の補足 ループによって作成されるすべて の関数値は、同じ変数を「補足」し て共有します。 つまり特定の瞬間の値ではなく、 アドレス化可能なメモリの位置を 共有します。

Slide 25

Slide 25 text

Local variable 1 package main import ( "fmt" ) func main() { x := "hello" for _, x := range x { x := x + 'A' - 'a' fmt.Printf("%c", x) } } https://play.golang.org/p/ljulBLJZs6k Compilable? 02. Traps and explanations

Slide 26

Slide 26 text

P52 2.7 スコープ レキシカルブロックは関数内で任 意の深さまでネストできますので、 一つのローカル宣言が別のロー カル宣言を隠蔽することができま す。

Slide 27

Slide 27 text

Local variable 2 package main import ( "fmt" ) func main() { if x := 10; x == -1 { // do something... } else if y := 20; y == -1 { // do something... } else { fmt.Printf("%d %d", x, y) } } https://play.golang.org/p/6NH44WjXOz- Compilable? 02. Traps and explanations

Slide 28

Slide 28 text

P52 2.7 スコープ for文と同様に、if文とswitch文 もそれぞれの本体ブロックに加え て暗黙のブロックを生み出しま す。

Slide 29

Slide 29 text

Notification channel ● Which best? ○ done := make(chan int) ○ done := make(chan struct{})

Slide 30

Slide 30 text

Size of empty struct is zero package main import ( "fmt" "reflect" ) func main() { var i int var s struct{} fmt.Printf("%v\n", reflect.TypeOf(i).Size()) // 4 fmt.Printf("%v\n", reflect.TypeOf(s).Size()) // 0 } https://play.golang.org/p/nZqAFEZs48J チャネルの型は重 要ではありません ので、大きさがゼロ であるstruct{}を 使います。 P278 8.6 例:平行ウェブクローラ 02. Traps and explanations

Slide 31

Slide 31 text

公開されていない フィールドもリフレ クションでは見える ことに注意してくだ さい。 Visibility private field package main import ( "fmt" "os" "reflect" ) func main() { v := reflect.ValueOf(os.Stderr) // os.File.(*file).name fmt.Printf("%v\n", v.Elem().Field(0).Elem().FieldByName("name")) } https://play.golang.org/p/u8-5-kWyzGI P387 12.3 Display:再帰的な値の表示 02. Traps and explanations

Slide 32

Slide 32 text

Today’s Summary SECTION THREE

Slide 33

Slide 33 text

Today's summary ● Gopherくんは不滅 ● 一度はハマる落とし穴/仕様を紹介 ● そんな落とし穴も本で言及されていた ● 体系的な言語仕様の学習は大切 03. Today’s summary