コンテンツにスキップ

Go入門30日間で学ぶべきこと:goroutine・defer・エラーハンドリング・net/http

概要

Go を始めて 30 日間で学ぶべき最重要概念を厳選したリスト。「Go の並行処理が本質なので Day 1 から goroutine を学べ」という実践的なアドバイス。

詳細

1. goroutine + channel(並行処理)

Go の最大の強みであり、最初に学ぶべき概念。

// goroutine: go キーワードで並行実行
func fetchData(url string, ch chan<- string) {
    resp, _ := http.Get(url)
    defer resp.Body.Close()
    body, _ := io.ReadAll(resp.Body)
    ch <- string(body)
}

func main() {
    ch := make(chan string, 2)
    go fetchData("https://api1.example.com", ch)  // 並行実行
    go fetchData("https://api2.example.com", ch)

    result1 := <-ch  // チャネルから受信(ブロック)
    result2 := <-ch
    fmt.Println(result1, result2)
}

2. defer(クリーンアップの制御)

関数の終了時に必ず実行される。パニック時にも動作する。

func readFile(path string) ([]byte, error) {
    f, err := os.Open(path)
    if err != nil {
        return nil, err
    }
    defer f.Close()  // ← 関数が終わる時に必ず閉じる(エラーでも同様)

    return io.ReadAll(f)
}

3. エラーハンドリング

Go は例外を throw しない。エラーは戻り値として明示的に扱う。

// 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
}
// エラーを無視すると lint で警告(errcheck)

4. net/http(HTTP サーバー)

標準ライブラリだけで本番 HTTP サーバーが作れる。

package main

import (
    "encoding/json"
    "net/http"
)

func main() {
    mux := http.NewServeMux()

    // Go 1.22+: メソッドとパスパターンをサポート
    mux.HandleFunc("GET /users/{id}", func(w http.ResponseWriter, r *http.Request) {
        id := r.PathValue("id")
        w.Header().Set("Content-Type", "application/json")
        json.NewEncoder(w).Encode(map[string]string{"id": id})
    })

    http.ListenAndServe(":8080", mux)
}

5. その他の重要ポイント

// interface: 暗黙的な実装(implements キーワード不要)
type Writer interface {
    Write(p []byte) (n int, err error)
}

// struct embedding: 継承に近い合成
type Logger struct {
    *log.Logger
    prefix string
}

// context: タイムアウトとキャンセルの伝播
func doWork(ctx context.Context) error {
    select {
    case <-ctx.Done():
        return ctx.Err()
    case result := <-doHeavyWork():
        return nil
    }
}

なぜ重要か / いつ使うか

  • Go を初めて学ぶときの学習優先度の整理
  • 「Go で何から学べばいいか」と聞かれた後輩への回答
  • 他言語からの移行時に「Go らしい書き方」を掴むとき