Tour of Goをさらっと流したあとで、開発してみて詰まったところのまとめです。
多次元配列の初期化したい
型のあとに{}
を渡してあげればよいです。
例えば2次元配列の場合は{{1, 0}, {0, 1}}
みたいな感じで書けば良いです。
int配列の場合は、{}
とすると0で初期化されます。
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]]
多次元スライスの場合も同様です。
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
になる
package hoge
import "fmt"
func PrintName() {
fmt.Println("hoge.fuga")
}
パッケージ化したものはimportで読み込むと、
パッケージ名のプレフィクスをつけて関数などが呼び出せるようになります。
import "../piyo"
みたいなこともできます。
package main
import "./hoge"
func main() {
hoge.PrintName()
}
関数や構造体をパッケージ外から呼び出したい
名前の先頭を大文字にする(エクスポート)とパッケージ外から呼び出せます。
先程のものに少し手を加えます。
package hoge
import "fmt"
// 同一パッケージ内からは呼べる
func printName() {
fmt.Println("hoge.fuga")
}
// 他のパッケージからも呼べる
func PrintName() {
fmt.Println("hoge.fuga")
}
package main
import "./hoge"
func main() {
//hoge.printName()
// #=> cannot refer to unexported name hoge.printName
hoge.PrintName()
}
intをstringにしたい
10進数で文字列型に変換したい場合は、strconv.Itoa(i int)
を使います。
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文のスコープ内で同じ名前で別の変数を再定義することになります。
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
を使います。
対話処理をしたい場合は、関数にして必要なときに呼び出せばよさそうです。
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
で回してあげると順番通り出力できます。
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を使うのが便利でした。
参考
Go言語のスライスを理解しよう
シュッと golang に入門する話
Go でファイルを1行ずつ読み込む(csv ファイルも)
Go 1 Release Notes: Returns and shadowed variables
Golangでの文字列・数値変換
[Go] 構造体の初期化方法まとめ
The Go Blog: Iteration order