コンテンツにスキップ

Go/識別子のスコープ

出典: フリー教科書『ウィキブックス(Wikibooks)』
< Go

Goにおける識別子のスコープは、特定の識別子(変数名、関数名、型名など)がコードのどの部分から参照可能かを決定するものです。Goには主に以下の3つのスコープがあります。

  1. ブロック・スコープ (Block Scope)
  2. パッケージ・スコープ (Package Scope)
  3. ユニバース・スコープ (Universe Scope)

1. ブロック・スコープ (Block Scope)

[編集]

ブロック・スコープは、最も限定的なスコープです。{}で囲まれたブロック内で宣言された識別子(変数、定数など)は、そのブロック内でのみ有効です。

特徴
  • if文、for文、switch文、関数本体などのブロック内で宣言された変数や定数。
  • そのブロックが終了すると、識別子はスコープ外となり、アクセスできなくなります。
  • ネストされたブロックでは、外側のブロックの識別子にアクセスできますが、内側のブロックで同じ名前の識別子を宣言すると、内側の識別子が優先されます(シャドーイング)。
package main

import "fmt"

func main() {
    x := 10 // main関数のブロックスコープ

    if x > 5 {
        y := 20 // if文のブロックスコープ
        fmt.Println("x:", x) // アクセス可能
        fmt.Println("y:", y) // アクセス可能
    }

    // fmt.Println("y:", y) // エラー: yはifブロック外ではアクセスできない
}

func anotherFunc() {
    // fmt.Println("x:", x) // エラー: xはmain関数のブロックスコープに限定される
}

2. パッケージ・スコープ (Package Scope)

[編集]

パッケージ・スコープは、特定のパッケージ内で有効なスコープです。Goでは、識別子名の先頭の文字が大文字か小文字かによって、その可視性が決まります。

  • 公開(エクスポート)された識別子:
    • 識別子の最初の文字が大文字の場合、その識別子はパッケージ外からも参照可能です。
    • 他のパッケージからパッケージ名.識別子の形式でアクセスできます。
    • 関数、変数、定数、型などが該当します。
  • 非公開(エクスポートされない)識別子:
    • 識別子の最初の文字が小文字の場合、その識別子は宣言されたパッケージ内でのみ参照可能です。
    • 他のパッケージからはアクセスできません。
特徴
  • パッケージレベル(どの関数やブロックにも属さない)で宣言された識別子に適用されます。
  • 同じパッケージ内のどのファイルからでもアクセス可能です。
// mypackage/some_file.go
package mypackage

import "fmt"

const PublicConst = "公開定数" // パッケージ外からアクセス可能
var privateVar = 10         // パッケージ内でのみアクセス可能

func PublicFunction() { // パッケージ外からアクセス可能
    fmt.Println("これは公開関数です。")
    fmt.Println("privateVar:", privateVar) // パッケージ内なのでアクセス可能
}

func privateFunction() { // パッケージ内でのみアクセス可能
    fmt.Println("これは非公開関数です。")
}
// main.go (別のパッケージ)
package main

import (
    "fmt"
    "your_module/mypackage" // mypackageをインポート
)

func main() {
    fmt.Println(mypackage.PublicConst)     // アクセス可能
    mypackage.PublicFunction()             // アクセス可能

    // fmt.Println(mypackage.privateVar)   // エラー: 非公開なのでアクセスできない
    // mypackage.privateFunction()         // エラー: 非公開なのでアクセスできない
}

3. ユニバース・スコープ (Universe Scope)

[編集]

ユニバース・スコープは、Go言語全体でどこからでも参照可能な識別子に適用されます。これらはGo言語が事前に定義している組み込みの型、関数、定数などです。

  • 組み込み型: int, string, bool, float64, error など
  • 組み込み関数: len(), cap(), make(), new(), append(), panic(), recover(), print(), println() など
  • 組み込み定数: true, false, nil, iota など

これらの識別子は、どのパッケージやブロックからでも特別な宣言なしに利用できます。

スコープの優先順位

[編集]

Goでは、スコープがネストされている場合、より内側のスコープで宣言された識別子が、外側のスコープで同じ名前の識別子が存在しても優先されます。これを「シャドーイング(shadowing)」と呼びます。

package main

import "fmt"

var name = "グローバル" // パッケージスコープ

func main() {
    name := "ローカル" // main関数のブロックスコープ (シャドーイング)
    fmt.Println(name) // "ローカル" が出力される

    if true {
        name := "さらにローカル" // if文のブロックスコープ (さらにシャドーイング)
        fmt.Println(name) // "さらにローカル" が出力される
    }

    fmt.Println(name) // "ローカル" が出力される (ifブロックを抜けたため)
}

まとめ

[編集]
  • ブロック・スコープ: {}内で有効。最も限定的。
  • パッケージ・スコープ: パッケージ内で有効。大文字で始まる識別子は公開され、小文字で始まる識別子は非公開。
  • ユニバース・スコープ: Go言語全体で有効な組み込み識別子。

これらのスコープルールを理解することで、Goプログラムの可読性を高め、予期せぬ名前の衝突を避けることができます。