Go言語のelseを使った条件分岐の方法についてわかりやすく解説

スポンサーリンク
スポンサーリンク
amazon
スマイルSALE
--:--:--
ad. 価格範囲を指定して商品を探せます

elseの概要

条件がfalseのときに実行する処理を書くGoの予約語

else

概要 elseは、if文の条件評価式が偽(false)と判定された場合に、代替として実行する制御フローのコードブロックを定義するために使用します。

  • 先行する if(または else if)の検証結果が満たされなかった場合の「最終的な受け皿(デフォルト処理)」として機能する。
  • 単独で宣言することはできず、必ず if ステートメントのコードブロック(})に直接接続して記述しなければならない。
  • else if のチェインを構築することで、排他的な(いずれか1つのみが実行される)多方向の分岐構造を形成できる。

elseの考え方をイメージで理解

基本的なelseの使い方(二者択一の分岐制御)

条件が真(true)であるか偽(false)であるかに応じて、実行する処理を完全に2つのルートへ分断する最も基本的なパターンです。

package main

import "fmt"

func main() {
    num := 10

    if num > 10 {
        // 条件が真(true)の場合に実行
        fmt.Println("10より大きい数値です")
    } else {
        // 条件が偽(false)の場合に実行
        fmt.Println("10以下の数値です")
    }
}

構造解説:

  • num > 10 という評価式の型は bool です。今回 num は 10 であるため、評価結果は false(偽)となります。
  • これにより、if 直後の波括弧内のコードは完全に無視され、else にカプセル化されているブロックが代替として呼び出されます。

実行結果:

10以下の数値です

else ifを用いた多者択一の排他条件チェイン

3つ以上の境界値や状態を段階的に評価する場合、else if を間に挟むことで上から順番に条件をスキャンさせることができます。

package main

import "fmt"

func main() {
    score := 75

    if score >= 90 {
        fmt.Println("評価: 優 (A)")
    } else if score >= 80 {
        fmt.Println("評価: 良 (B)")
    } else if score >= 70 {
        fmt.Println("評価: 可 (C)")
    } else {
        // 上記の条件すべてが偽(false)だった場合の最終ルート
        fmt.Println("評価: 不可 (D)")
    }
}

構造解説:

  • プログラムは最上段の score >= 90 から検証を始めます。これが false であるため次の else if score >= 80 へ進み、これも false であるためさらに次の score >= 70 へと流れます。
  • score >= 70 で初めて条件が true に確定するため、該当ブロックが実行され、それ以降の else 判定は評価されずに全体の構文から離脱します。

実行結果:

評価: 可 (C)

if文の簡易文脈(短縮構文)とelseのスコープ共有

Go言語では、if 条件式の評価の前に「初期化文」をセミコロン(;)で区切って記述できます。この初期化文で生成されたローカル変数は、後ろに続く else ブロックの内部でも有効に機能します。

package main

import "fmt"

func main() {
    // 変数「status」の宣言・初期化をif文のスコープ内に限定する
    if status := "unauthorized"; status == "authenticated" {
        fmt.Println("アクセスが許可されました。")
    } else {
        // if文の直前で生成された status 変数をそのまま利用可能
        fmt.Printf("拒否されました。現在の状態: %s\n", status)
    }

    // ここで status を参照しようとするとコンパイルエラーになる
    // fmt.Println(status) // error: undefined: status
}

構造解説:

  • status := "unauthorized"if-else 構造全体の生存期間(ライフタイム)にバインドされます。
  • 関数のグローバルな空間に変数を汚染させない(不要な変数を残さない)という最小権限の原則に則った、Go特有の非常にクリーンな設計パターンです。

実行結果:

拒否されました。現在の状態: unauthorized

学術的・設計的注意点

  • 改行配置の強制(セミコロン自動挿入機構の制約): Go言語のソースコードでは、else キーワードを独立した新しい行の先頭に記述すると、コンパイルエラー(syntax error: unexpected else)になります。これはGoコンパイラが解析時に行末へ自動的にセミコロン(;)を補完する仕様(Semicolon Injection Rule)を持っているためです。} の直後に改行を入れると、コンパイラが if 文の完全な終了とみなしてセミコロンを打ってしまうため、続く else が孤立して構文エラーを引き起こします。そのため、必ず } else { を1行の連続したトークンとして記述しなければなりません。
  • ガード節による「Happy Path」の維持とelse回避: ソフトウェア工学(クリーンコード)において、else はコードのネストを深くし、認知的複雑性を上げる原因として警戒される傾向にあります。特に関数内でエラーや例外的な条件を弾くだけの目的であれば、else ブロックの中に正常系ロジックを詰め込むのではなく、if err != nil { return } のように早期にリターン(アーリーリターン)させ、else をあえて記述せずに正常系(Happy Path)をインデントの浅いメインストリームに残すコーディングスタイルが推奨されます。

よくある質問(FAQ)

Q: else if を重ねるのと、switch文を使うのでは、内部の処理効率(パフォーマンス)に違いはありますか?
A: Go言語のコンパイラは非常にスマートなため、単純な値の比較による else if チェインであれば、内部的に switch 文と同様に効率的なジャンプテーブル等へ最適化されるケースが多く、実行速度に致命的な差が出ることは稀です。ただし、設計思想および可読性の観点からは、同一の変数に対する多方分岐であれば switch を使い、異なる条件式や複雑な論理演算が絡む分岐であれば if-else if を使う、という書き分けが最適です。
Q: 短縮構文(if initialization; condition)の中で既存の同名変数を宣言した場合、else側ではどちらが参照されますか?
A: if の初期化文で変数を短縮型宣言(:=)した場合、既存の外側のスコープにある同名変数とは異なる、新しいローカル変数が「シャドウイング(覆い隠し)」として生成されます。当然、それに連なる else ブロックの内部でも、このシャドウイングされた(if 構文内で新しく生成された)側の変数が最優先で参照されるため、意図しない値の混同を防ぐための注意が必要です。
Q: Go言語には、他言語にある「三項演算子(condition ? trueVal : falseVal)」のような簡潔なインライン記述はないのですか?
A: ありません。Go言語の設計者たちは「コードの可読性を最大化し、1つの目的を達成するための記述方法は常に1通りであるべきだ」という哲学(コンプレキシティの排除)を貫いたため、三項演算子の導入を意図的に見送りました。そのため、どれほど単純な二者択一であっても、必ず省略せずに if-else 構文を組み立てて記述する必要があります。

まとめ

  • else は、if に課された条件が満たされなかった場合に実行される代替制御フローを確定するための予約語。
  • Go言語の文法規則(セミコロン自動挿入機構)の制約上、直前の閉じ括弧と同一行(} else {)に記述することが必須。
  • 簡易文脈(初期化文)と組み合わせることで、if および else のコードブロック内だけで閉じたカプセル精度の高い変数の取り扱いが可能。
  • 過度な else if の累積はコードの認知的複雑性を高めるため、ガード節(早期離脱)の適用や switch 構文へのリファクタリングを適宜考慮することが重要となる。