go-control-flow について
Go の制御フロー、変数スコープ、ループ、switch、ブランク識別子を扱うコーディングスキルです。一般的な Go の書き方を適用し、スコープや制御フローの誤りを避ける開発者向けです。
主な機能
- 01条件文の初期化とスコープ
- 02ガード節と早期リターン
- 03短縮宣言とシャドーイング
- 04for と range の規則
- 05switch の脱出とブランク識別子
活用シーン
- 01if や switch 内に変数を限定
- 02短縮宣言のシャドーイング確認
- 03map や文字列の反復処理
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ cxuu/ golang-skills --skill go-control-flowインストール後、Claude Code で/go-control-flowを入力して読み込まれたか確認します。
同梱ファイルreferences/BLANK-IDENTIFIER.mdreferences/SWITCH-PATTERNS.md
詳細
Go の制御フロー
リソースのルーティング
references/SWITCH-PATTERNS.md- switch 文、型 switch、fallthrough、ラベル付き break を使用する場合に読みます。references/BLANK-IDENTIFIER.md-_、空 import、未使用のコンパイル時アサーション、意図的な破棄を使用する場合に読みます。
初期化文付きの if
if と switch は、省略可能な初期化文を受け取ります。これを使って、変数のスコープを条件ブロック内に限定します。
if err := file.Chmod(0664); err != nil {
log.Print(err)
return err
}
if の後の数行を超えて変数を使う必要がある場合は、変数を別途宣言し、通常の if を使います。
x, err := f()
if err != nil {
return err
}
// lots of code that uses x
エラー時のインデント(ガード節)
if 本体の末尾が break、continue、goto、または return の場合は、不要な else を省略します。成功時の処理はインデントせずに記述します。
f, err := os.Open(name)
if err != nil {
return err
}
d, err := f.Stat()
if err != nil {
f.Close()
return err
}
codeUsing(f, d)
if がすでに return している場合に、通常の処理を else の中に入れてはいけません。
再宣言と再代入
:= による短縮宣言では、同じスコープ内の変数を再宣言できます。
f, err := os.Open(name) // declares f and err
d, err := f.Stat() // declares d, reassigns err
変数 v は、すでに宣言されている場合でも、次の条件を満たせば := 宣言に含められます。
- 宣言が既存の
vと同じスコープ内にある - 値を
vに代入できる - 宣言によって、少なくとももう1つの変数が新たに作成される
変数のシャドーイング
警告:v が外側のスコープで宣言されている場合、:= はそれをシャドーイングする新しい変数を作成します。これはよくあるバグの原因です。
// Bug: ctx inside the if block shadows the outer ctx
if *shortenDeadlines {
ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
defer cancel()
}
// ctx here is still the original — the shadowed ctx didn't escape
// Fix: use = instead of :=
var cancel func()
ctx, cancel = context.WithTimeout(ctx, 3*time.Second)
for ループ
Go で使えるループ構文は for だけです。while、do-while、C スタイルの for を統合しています。
// Condition-only (Go's "while")
for x > 0 {
x = process(x)
}
// Infinite loop
for {
if done() { break }
}
// C-style three-component
for i := 0; i < n; i++ { ... }
range
range はスライス、マップ、文字列、チャネルを反復処理します。
for i, v := range slice { ... } // index + value
for k, v := range myMap { ... } // key + value (non-deterministic order)
for i, r := range "héllo" { ... } // byte index + rune (not byte)
for v := range ch { ... } // receives until channel closed
主なルール:
- 文字列に対する range はバイトではなくルーンを返します。
iはバイトオフセットです - マップに対する range の順序は非決定的です。順序に依存しないでください
- インデックスまたは値を破棄するには
_を使います:for _, v := range slice
並行代入
Go にカンマ演算子はありません。複数のループ変数には並行代入を使います。
for i, j := 0, len(a)-1; i < j; i, j = i+1, j-1 {
a[i], a[j] = a[j], a[i]
}
++ と -- は式ではなく文です。並行代入では使用できません。
switch:ラベル付き break
for ループ内の switch にある break は、switch だけを抜けます。外側のループを抜けるには、ラベル付き break を使います。
Loop:
for _, v := range items {
switch v.Type {
case "done":
break Loop // breaks the for loop
}
}
型 switch については、go-interfaces:型 switch を参照してください。
空識別子
エラーを安易に破棄してはいけません。その後に nil 参照によるパニックが発生する可能性があります。
コンパイル時のインターフェースアサーションは、go-interfaces に振り分けてください。
クイックリファレンス
| パターン | Go の慣用形 |
|---|---|
| 初期化文付き if | if err := f(); err != nil { } |
| 早期 return | if 本体が return する場合は else を省略 |
| 再宣言 | 同じスコープ + 新しい変数がある場合、:= は再代入する |
| シャドーイングの落とし穴 | 内側のスコープの := は新しい変数を作成する |
| 並行代入 | i, j = i+1, j-1 |
| 式なし switch | switch { case cond: } |
| カンマ区切りの case | case 'a', 'b', 'c': |
| fallthrough なし | デフォルトの動作(必要な場合は明示的に fallthrough) |
| switch 内のループを抜ける | break Label |
| 値を破棄する | _, err := f() |
| 副作用目的の import | import _ "pkg" |
| インターフェースの確認 | go-interfaces に振り分ける |
関連スキル
- エラーフロー:ガード節、早期 return、またはエラー優先のパターンを構成する場合は、go-error-handling を参照してください
- 型 switch:型 switch、comma-ok イディオム、またはインターフェースの充足確認を使用する場合は、go-interfaces を参照してください
- ネストの削減:ネストの深さを減らす場合や、書式に関する疑問を解決する場合は、go-style-core を参照してください
- 変数のスコープ:if-init、
:=による再宣言、または変数スコープの縮小を行う場合は、go-declarations を参照してください