Go言語を書き始めた最初の30日で学ぶべきこと
概要¶
Go言語を書き始めた最初の30日間で必ず押さえるべき重要概念のリスト。Yoshik氏が「これを学ぶべき」として挙げた項目を解説する。
詳細¶
1. goroutine + channel の基礎(Day 1 から)¶
Goの並行処理はgoroutineとchannelが中心。Day 1から学ぶべき理由は「Goの並行処理こそGoの本質」だから。
// goroutineの起動
go func() {
fmt.Println("並行実行")
}()
// channelで値を渡す
ch := make(chan int)
go func() { ch <- 42 }()
val := <-ch
fmt.Println(val) // 42
なぜ重要か: 他の言語のスレッドと異なり、goroutineは軽量(数KB)で何万個も起動できる。channelで安全に値を受け渡しすることでデータ競合を防ぐ。
2. defer(クリーンアップの制御)¶
deferはpanicが起きても実行される。リソース解放に使う。
func readFile(path string) error {
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close() // 関数終了時に必ず実行される
// ファイル処理...
return nil
}
注意点: deferはLIFO(後入れ先出し)で実行される。複数のdeferがある場合は最後に登録されたものから実行。
3. エラーハンドリング¶
Goには例外がない。エラーは戻り値として返す。
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("division by zero")
}
return a / b, nil
}
result, err := divide(10, 0)
if err != nil {
log.Printf("error: %v", err)
return
}
パターン: 関数は (result, error) を返す。呼び出し側は必ずエラーを確認する。errors.Is() / errors.As() でエラー種別を判定する。
4. interface(暗黙の実装)¶
Goのinterfaceは実装を宣言する必要がない(ダックタイピング)。
type Writer interface {
Write(p []byte) (n int, err error)
}
// File, bytes.Buffer, net.Conn など全て Writer を満たす
// 明示的な "implements Writer" の記述は不要
活用: テストでのモック作成、依存性の注入が容易になる。
5. テスト(標準パッケージ)¶
外部ライブラリ不要でテストが書ける。
// sum_test.go
func TestSum(t *testing.T) {
got := Sum(1, 2)
want := 3
if got != want {
t.Errorf("Sum(1, 2) = %d; want %d", got, want)
}
}
6. goroutineリーク¶
goroutineはcontextでキャンセルしないとリークする。
// 悪い例: goroutineが永遠に待ち続ける
go func() {
<-ch // chに誰も送信しなければリーク
}()
// 良い例: contextでキャンセル可能にする
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
go func() {
select {
case val := <-ch:
process(val)
case <-ctx.Done():
return // タイムアウト or キャンセルで終了
}
}()
7. ポインタ vs 値渡し¶
// 値渡し: コピーが作られる
func incrementValue(n int) int {
return n + 1
}
// ポインタ渡し: 元の値を変更できる
func incrementPointer(n *int) {
*n++
}
x := 10
incrementPointer(&x) // x は 11 になる
目安: 大きな構造体やミュータブルな操作はポインタ。小さな値型は値渡しでOK。
8. Go Modules¶
go mod init github.com/username/project # モジュール初期化
go get github.com/some/package # 依存追加
go mod tidy # 不要な依存を削除
なぜ重要か / いつ使うか¶
- Goを書き始めた最初の数週間で理解すると、後で「なぜこう書くのか」で迷わなくなる
- goroutineのリークはサービスのメモリ増大に直結する。最初から
contextの使い方を習得する - エラーハンドリングのパターンはGoコードのほぼ全ての関数に登場する。早期に慣れる