【Golang】Getting Started
言語の特徴
Hello World
package main import "fmt" func main() { fmt.Println("Hello World") }
パッケージ
- パッケージ外に公開する識別子は先頭を大文字にする
- パッケージは複数ファイルから構成されても良い
- init関数
- パッケージの初期化用に定義できる関数
- 引数も戻り値もない
- ひとつのパッケージに複数定義できる(その場合の実行順序は定義順)
package main import "fmt" func init() { fmt.Println("init") } func main() { fmt.Println("main") } // 実行結果 // init // main
import
- 別名を指定してインポート
import f "fmt" f.Println("test")
- パッケージ名の省略
import . "fmt" Println("test")
宣言
- var:変数宣言
- const:定数宣言
- type:型宣言
- func:関数宣言
データ型
- bool
- int8, int16, int32, int64
- uint8, uint16, uint32, uint64
- int(実装依存)
- uint(実装依存)
- uintptr(ポインタの値を格納)
- float32
- float64
- rune(Unicodeコードポイントを表す整数型。int32の別名。)
- string
ポインタ
Cと使い方ほぼ同じ。ただしアドレスの加算減算はできない。
var n int = 1 var p *int = &n *p = 5 fmt.Printf("n = %d\n", *p) // 5
定数
- 型あり定数
const n int64 = 3 または const n = int64(3)
- 型なし定数
const n = 3
- iota
- 0オリジンの連番を採番
const ( X = iota // 0 Y // 1 Z // 2 )
配列
- 配列を関数の引数に渡す際は参照渡しではなくコピーが渡される
var a1 [5]int // すべてゼロ値で初期化 a2 := [5]int{} // すべてゼロ値で初期化 a3 := [5]int{1, 2, 3, 4, 5} a4 := [...]int{1, 2, 3} // 要素数の省略 (結果として[3]int型となる) a5 := [...]int{5: -1} // インデックスを指定して値を設定({0,0,0,0,0,-1})
スライス
- 可変長配列を表現
- 容量を超えた要素数を追加すると、新たにメモリ領域を確保し、格納していた全データを新しいメモリ領域にコピーする(アドレスが変わる)
- 事前に容量を大きく確保しておけば、新たなメモリ確保およびコピーが無くなる分の高速化が図れるが、不要にメモリを確保することにもなるので調整次第
var sli []int // スライスの宣言 sli = make([]int, 5, 10) // 要素数5、容量10のスライスを生成 sli2 := []int{1, 2, 3, 4, 5} // makeを使わないスライス生成リテラル fmt.Println(sli) // [0 0 0 0 0 0 0 0 0 0] 初期値はゼロ値 fmt.Println(len(sli)) // lenで要素数を取得 fmt.Println(cap(sli)) // capで容量を取得 // 要素の追加はappend sli1 := []int{1,2,3} sli2 := []int{5,6,7} s := append(sli1, 4) // [1,2,3,4] s = append(s, sli2...) // ...で展開してスライス自体を追加 fmt.Println(s) // [1,2,3,4,5,6,7]
- 配列とスライス
- 配列やスライスをもとに、新たなスライスを生成できる
a := [5]int{1, 2, 3, 4, 5} sli := a[2:4] // [3, 4]
- 文字列とスライス
- 文字列からスライスを生成できる
- 文字単位ではなくバイト単位となることに注意
s := "あいうえお" // それぞれ3バイトのマルチバイト文字 sli := s[3:9] // いう
マップ
var m map[string]int m = make(map[string]int) m["Taro"] = 18 m["Hanako"] = 24 fmt.Println(m) m1 := map[string]int{ "Taro": 18, "Hanako": 24, } delete(m1, "Hanako") // 要素の削除
構造体
type Person struct { Name string Age int } var Taro Person Taro.Name = "Taro" Taro.Age = 18 hanako := Person{"Hanako, 24} // 構造体リテラル Jiro := Person{Name: "Jiro", Age: 32}
関数
func funcA(x, y int) (string, error) { // 処理 return "success", nil }
- 無名関数
f := func(a, b int) int { return a + b } fmt.Println(f(3, 5))
func counter() func() int { var num int return func() int { num = num + 1 return num } } func main() { c1 := counter(); fmt.Println(c1()) // 1 fmt.Println(c1()) // 2 fmt.Println(c1()) // 3 c2 := counter(); fmt.Println(c2()) // 1 fmt.Println(c2()) // 2 fmt.Println(c2()) // 3 }
defer
- 関数の終了時に実行する式を登録できる
- 複数登録時は、最後に登録された式から実行される
func main() { defer fmt.Println("AAA") defer fmt.Println("BBB") defer fmt.Println("CCC") fmt.Println("DDD") } // 出力結果 // DDD // CCC // BBB // AAA
panic
func panic(v interface{})
- 即座にランタイムエラーを発生させる
- 引数はエラーメッセージなどに使用できる
- panicまでに登録されたdeferは実行される
recover
- panicから回復することができる
- deferと組み合わせて使われる
- recoverの戻り値はnil(panicが起きていない)or panicの引数
- recoverを実行するとpanicから復帰する
func panicFunc() { defer func() { if x := recover(); x != nil { // panicが起きた fmt.Println("recover") } }() panic("error") } func main() { fmt.Println("start") panicFunc() fmt.Println("end") // 実行される } // 出力結果 // start // recover // end
メソッド
func (u *User) say() { if u == nil { fmt.Println("Invalid User") } else { fmt.Println(u.Name) } } func main() { u := User{"Taro"} u.say() }
インタフェース
- メソッドのシグネチャのみ定義
type Creature interface { Say(str string) }
- 空インタフェース interface{}
- すべての値を代入できる
- 演算はできない
var any interface{} any = 10 any = true
ゴルーチン
- スレッドより小さいGo独自の処理単位
- 関数実行の前にgoを付与するだけでゴルーチンを生成できる
func say() { fmt.Println("Hello") } func main() { go say() fmt.Printf("CPU num : %d\n", runtime.NumCPU()) fmt.Printf("Goroutine num : %d\n", runtime.NumGoroutine()) // 2 }
チャネル
テスト
- パッケージ内の*_test.goファイルがテスト対象
- テストの種類
- Testで始まるテスト関数:ロジックのテスト
- Benchmarkで始まるベンチマーク関数:性能のテスト
- Exampleで始まるコード例関数:ドキュメントの提供
func isEven(a int) bool { return a%2 == 0 } func TestIsEven(t *testing.T) { type args struct { a int } tests := []struct { name string args args want bool }{ {"case 1", args{2}, true}, {"case 2", args{3}, false}, {"case 3", args{4}, true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := isEven(tt.args.a); got != tt.want { t.Errorf("isEven() = %v, want %v", got, tt.want) } }) } }