Go言語入門してつまったアレコレ


[Tour of Go](https://go-tour-jp.appspot.com)をさらっと流したあとで、開発してみて詰まったところのまとめです。


### 多次元配列の初期化したい

型のあとに`{}`を渡してあげればよいです。
例えば2次元配列の場合は`{{1, 0}, {0, 1}}`みたいな感じで書けば良いです。

int配列の場合は、`{}`とすると0で初期化されます。


```go
var matrix [2][2]int = [2][2]int {}
// #=> [[0 0] [0 0]]

matrix2 := [2][2]int {}
// #=> [[0 0] [0 0]]

matrix3 := [3][2]int {{0, 1}, {}, {2, 3}}
// #=> [[0 1] [0 0] [2 3]]
```

多次元スライスの場合も同様です。

```go
package main

import "fmt"

func main() {
	var slice1 [][]int = make([][]int, 3)
	fmt.Println(slice1)
	// #=> [[] [] []]

	slice2 := [][]int{{}, {}, {}}
	fmt.Println(slice2)
	// #=> [[] [] []]
}
```




### ファイル分割したい

`main.go`がどんどん肥大化していって辛い。
そんな時は、パッケージ化をしてファイルを分割します。


#### パッケージ化


パッケージ化する場合は、パッケージ名でディレクトリを作成し、
その中に切り出したgoファイルを作っていきます。


```
.── main.go
└── hoge
     └── fuga.go
```

packageは`hoge`になる


```go:hoge/fuga.go
package hoge

import "fmt"

func PrintName() {
        fmt.Println("hoge.fuga")
}
```

パッケージ化したものはimportで読み込むと、
パッケージ名のプレフィクスをつけて関数などが呼び出せるようになります。
`import "../piyo"`みたいなこともできます。


```go:main.go
package main

import "./hoge"

func main() {
        hoge.PrintName()
}
```


### 関数や構造体をパッケージ外から呼び出したい

名前の先頭を大文字にする(エクスポート)とパッケージ外から呼び出せます。
先程のものに少し手を加えます。


```go:hoge/fuga.go
package hoge

import "fmt"

// 同一パッケージ内からは呼べる
func printName() {
        fmt.Println("hoge.fuga")
}

// 他のパッケージからも呼べる
func PrintName() {
        fmt.Println("hoge.fuga")
}
```

```go:main.go
package main

import "./hoge"

func main() {
        //hoge.printName()
        // #=> cannot refer to unexported name hoge.printName
        hoge.PrintName()
}
```

### intをstringにしたい

10進数で文字列型に変換したい場合は、`strconv.Itoa(i int)`を使います。

```go:main.go
package main

import (
"fmt"
"strconv"
)

func main() {
	i := 0
	fmt.Println("int: " + string(i))
    // #=> int: 
	fmt.Println("int: " + strconv.Itoa(i))
    // #=> int: 0
}
```



### for文における変数のスコープ(シャドーイング)


for文で同一の変数を使いまわしたい場合にやってしまったミスです。
`:=`を使うとfor文のスコープ内で同じ名前で別の変数を再定義することになります。



```go:main.go
package main

import (
        "fmt"
        "strconv"
)

func main() {
        count := 0
        list := []string{}

        // `:=`ではlistが更新されない
        for count < 2 {
                list := append(list, strconv.Itoa(count))
                count += 1
                fmt.Println(list)
        }
        // #=> [0]
        //     [1]

        count = 0
        list = []string{}

        // `=`でlistが更新される
        for count < 2 {
                list = append(list, strconv.Itoa(count))
                count += 1
                fmt.Println(list)
        }
        // #=> [0]
        //     [0 1]
}
```


### 標準入力から対話的に1行ずつ読みたい

コマンドラインで実行して、標準入力から1行ずつ読み込みたい場合は、`bufio.NewReader`を使います。
対話処理をしたい場合は、関数にして必要なときに呼び出せばよさそうです。


```go
package main

import (
        "bufio"
        "fmt"
        "os"
)

func main() {
        fmt.Print("Please type something\ngo> ")
        reader := bufio.NewReader(os.Stdin)
        line, _, err := reader.ReadLine()
        if err != nil {
                fmt.Println(err)
                os.Exit(1)
        }
        fmt.Println(string(line))
}
```

### mapのキーをソート順で表示したい

`map[int]T`みたいなmapに` for range`を使った場合、取得できるkeyの順序制約はありません。
そのため`fmt.Print`してみたら実行毎に順番が変わります。

ちゃんとkeyをソートして使いたい場合は、
keyを取り出してソートしたものを`for range`で回してあげると順番通り出力できます。

```go:main.go
package main

import (
	"fmt"
	"sort"
)

func main() {
	m := map[int]int{
		3: 0,
		1: 0,
		2: 0,
	}

	// keyの順番で出力されない
	for k, v := range m {
		fmt.Printf("|%v: %v|", k, v)
	}
	// #=> |3: 0||1: 0||2: 0|

	fmt.Println()

	// mapのkeyをスライスで取得してソートし、
	// rangeでループさせて順番に取得する
	var keys []int
	for k := range m {
		keys = append(keys, k)
	}
	sort.Ints(keys)

	// To perform the opertion you want
	for _, k := range keys {
		fmt.Printf("|%v: %v|", k, m[k])
	}
	// #=> |1: 0||2: 0||3: 0|
}
```
### その他


開発中にちょっと関数を試してみたいときは[Go Playground](http://play.golang.org/)を使うのが便利でした。


### 参考


[Go言語のスライスを理解しよう](http://www.slideshare.net/yasi_life/go-14075425)
[シュッと golang に入門する話](http://sixeight.hatenablog.com/entry/2015/03/16/032222)
[Go でファイルを1行ずつ読み込む（csv ファイルも）](http://qiita.com/ikawaha/items/28186d965780fab5533d)
[Go 1 Release Notes: Returns and shadowed variables](https://golang.org/doc/go1#shadowing)
[Golangでの文字列・数値変換](http://matope.hatenablog.com/entry/2014/04/22/101127)
[[Go] 構造体の初期化方法まとめ](http://qiita.com/cotrpepe/items/b8e7f70f27813a846431)
[The Go Blog: Iteration order](http://blog.golang.org/go-maps-in-action#TOC_7.)