Go/var
varキーワードはGoにおいて変数宣言のために使用される基本的なキーワードです。この総合ガイドでは、varキーワードのすべての用途と他のキーワードとの組み合わせ、さまざまなユースケースについて詳しく説明します。
1. 基本的な変数宣言
[編集]1.1 単一変数の宣言
[編集]var name string var age int var salary float64 var isActive bool
最も基本的な形式として、varキーワードを使用して型を明示的に指定した変数を宣言できます。
1.2 初期値を持つ変数の宣言
[編集]var name string = "田中太郎" var age int = 30 var salary float64 = 45000.50 var isActive bool = true
宣言時に初期値を与えることができます。
1.3 型推論による変数宣言
[編集]var name = "田中太郎" // string型と推論される var age = 30 // int型と推論される var salary = 45000.50 // float64型と推論される var isActive = true // bool型と推論される
初期値を指定する場合、型を省略すると初期値から型が推論されます。
1.4 複数変数の宣言
[編集]var firstName, lastName string var width, height int var x, y, z float64
同じ型の複数の変数を一度に宣言できます。
1.5 異なる型の複数変数の宣言
[編集]var ( name string age int salary float64 isActive bool )
括弧を使用して、異なる型の複数の変数をグループ化して宣言できます。
1.6 複数変数の初期化
[編集]var firstName, lastName = "太郎", "田中" var width, height, depth = 10, 20, 15
複数の変数に同時に初期値を設定できます。
1.7 異なる型の複数変数の初期化
[編集]var ( name = "田中太郎" age = 30 salary = 45000.50 isActive = true )
括弧内で型推論を使用して複数の変数を初期化できます。
2. var と短縮変数宣言の比較
[編集]2.1 短縮変数宣言(:=)
[編集]name := "田中太郎" age := 30 salary := 45000.50 isActive := true
関数内では、:=を使用したより簡潔な短縮変数宣言が一般的に使用されます。
2.2 varと短縮宣言の使い分け
[編集]// パッケージレベルではvarが必要 var globalCounter int func main() { // 関数内部では「:=」も使用可能 localCounter := 0 // 既存の変数に新しい値を代入する場合は<code>[[../=|=]]</code> localCounter = 1 }
varはパッケージレベルと関数内部の両方で使用できますが、:=は関数内部でのみ使用できます。
3. var キーワードとスコープ
[編集]3.1 パッケージレベル(グローバル)変数
[編集]package main // パッケージレベル変数 var ( maxConnections = 100 timeout = 30 serviceName = "UserAPI" ) func main() { // パッケージレベル変数にアクセス println(serviceName, maxConnections) }
varを使用してパッケージレベルの変数を宣言できます。
3.2 ブロックスコープ変数
[編集]func processData() { var result string if data, err := getData(); err == nil { var temp = processRawData(data) result = formatData(temp) } else { // dataとtemp変数はここでは見えない result = "エラー発生" } // resultはこのスコープで利用可能 return result }
varで宣言された変数は、宣言されたブロック内でのみアクセス可能です。
4. var キーワードと型
[編集]4.1 基本型の変数
[編集]var i int var u uint var f float32 var s string var b bool var r rune var by byte
基本的な組み込み型の変数を宣言できます。
4.2 複合型の変数
[編集]var arr [5]int var slice []int var m map[string]int var ch chan int var ptr *int
配列、スライス、マップ、チャネル、ポインタなどの複合型の変数も宣言できます。
4.3 カスタム型の変数
[編集]type Person struct { Name string Age int } var person Person var people []Person
typeキーワードで定義したカスタム型の変数を宣言できます。
4.4 インターフェース型の変数
[編集]type Reader interface { Read(p []byte) (n int, err error) } var r Reader
インターフェース型の変数も宣言できます。
5. var キーワードと初期化
[編集]5.1 ゼロ値による初期化
[編集]var i int // 0 var f float64 // 0.0 var b bool // false var s string // "" var p *int // nil var slice []int // nil var m map[string]int // nil var ch chan int // nil
varで宣言された変数は自動的に型のゼロ値に初期化されます。
5.2 コンポジット・リテラルによる初期化
[編集]var arr = [3]int{1, 2, 3} var slice = []string{"a", "b", "c"} var m = map[string]int{"one": 1, "two": 2} var p = Person{Name: "田中太郎", Age: 30}
コンポジット・リテラルを使用して複合型変数を初期化できます。
5.3 初期化関数による初期化
[編集]var complexData = initComplexData() func initComplexData() map[string]interface{} { // 複雑な初期化ロジック result := make(map[string]interface{}) // ... 初期化処理 ... return result }
関数呼び出しの結果で変数を初期化できます。
6. var キーワードと他のキーワードの組み合わせ
[編集]6.1 var と const の使い分け
[編集]const pi = 3.14159 // 定数:変更不可 var ratio = 1.618 // 変数:変更可能 func updateRatio() { ratio = 1.62 // OK // pi = 3.14 // エラー:定数は再代入できない }
変更が必要な値にはvarを、変更不要な値にはconstを使用します。
6.2 var と func の組み合わせ
[編集]// 関数型の変数 var handler func(string) string func init() { handler = func(s string) string { return "処理結果: " + s } }
関数型の変数を宣言して、後で関数値を代入できます。
6.3 var と go (ゴルーチン) の組み合わせ
[編集]var results = make(chan string, 10) func processInBackground() { go func() { // バックグラウンド処理 results <- "処理完了" }() }
ゴルーチンでアクセスする変数を事前に宣言できます。
6.4 var と defer の組み合わせ
[編集]func processFile(path string) error { var file *os.File var err error file, err = os.Open(path) if err != nil { return err } defer file.Close() // ファイル処理... return nil }
6.5 var と type の組み合わせ
[編集]var data struct { Name string Age int } // 匿名構造体の変数を宣言して初期化 var config = struct { Host string Port int }{ Host: "localhost", Port: 8080, }
typeキーワードを使わずに匿名構造体の変数を宣言できます。
6.6 var と range の組み合わせ
[編集]var sum int var numbers = []int{1, 2, 3, 4, 5} func calculateSum() int { for _, num := range numbers { sum += num } return sum }
rangeループで使用する変数や集計変数を事前に宣言できます。
6.7 var と switch の組み合わせ
[編集]var dayType string var weekday = time.Now().Weekday() func getDayType() string { switch weekday { case time.Saturday, time.Sunday: dayType = "休日" default: dayType = "平日" } return dayType }
switch文で使用する変数を事前に宣言できます。
6.8 var と if の組み合わせ
[編集]var err error var data []byte func processIfValid() { data, err = ioutil.ReadFile("config.json") if err != nil { log.Fatal(err) } if len(data) > 0 { // データ処理... } }
if文で使用する変数を事前に宣言できます。
7. var キーワードと特殊パターン
[編集]7.1 nil の明示的代入
[編集]var slice []int = nil var m map[string]int = nil var ch chan int = nil var err error = nil var ptr *int = nil
明示的にnilを代入できますが、通常は冗長と見なされます。
7.2 ブランク識別子(_)との組み合わせ
[編集]var _, found = cache["key"] var _, err = os.Stat("file.txt")
不要な戻り値を破棄するためにブランク識別子と組み合わせて使用できます。
7.3 シャドウイング(変数の隠蔽)
[編集]var err error // 外側のスコープのerr func process() { if data, err := getValue(); err == nil { // 内側のerrが外側のerrを隠す // ... } // ここでは外側のerrが見える }
内側のスコープで同名の変数を宣言すると、外側の変数は一時的に隠されます。これは注意が必要なパターンです。
7.4 空白の変数宣言
[編集]var names []string // 空のスライス(nil) var names = []string{} // 空のスライス(非nil) var m map[string]int // 空のマップ(nil) var m = map[string]int{} // 空のマップ(非nil)
nilスライス/マップと空のスライス/マップには違いがあります。
8. 実践的なユースケース
[編集]8.1 フラグ変数
[編集]var ( isDebug = false verbose = false ) func init() { flag.BoolVar(&isDebug, "debug", false, "デバッグモードを有効にする") flag.BoolVar(&verbose, "verbose", false, "詳細な出力を有効にする") flag.Parse() }
コマンドラインフラグとして使用する変数を宣言します。
8.2 グローバル設定
[編集]var ( config struct { Server struct { Host string Port int } Database struct { DSN string } } ) func init() { // 設定ファイルからconfigを読み込む loadConfig() }
アプリケーション全体で共有される設定を保持する変数を宣言します。
8.3 シングルトンパターン
[編集]var ( db *sql.DB dbOnce sync.Once ) func GetDB() *sql.DB { dbOnce.Do(func() { var err error db, err = sql.Open("postgres", "connection-string") if err != nil { log.Fatal(err) } }) return db }
「sync.Once」と組み合わせて、遅延初期化されるシングルトンパターンを実装できます。
8.4 依存関係の注入
[編集]var ( userRepo UserRepository authService AuthService ) func SetupDependencies(repo UserRepository, auth AuthService) { userRepo = repo authService = auth }
テストや設定変更が容易になるよう、依存関係を外部から注入できる変数を宣言します。
8.5 キャッシュ
[編集]var ( cache = make(map[string]interface{}) cacheMutex sync.RWMutex ) func GetFromCache(key string) (interface{}, bool) { cacheMutex.RLock() defer cacheMutex.RUnlock() val, found := cache[key] return val, found } func SetToCache(key string, value interface{}) { cacheMutex.Lock() defer cacheMutex.Unlock() cache[key] = value }
アプリケーション全体で共有されるキャッシュを宣言します。
8.6 カウンターや統計
[編集]var ( requestCount int64 errorCount int64 ) func incrementRequestCount() int64 { return atomic.AddInt64(&requestCount, 1) } func incrementErrorCount() int64 { return atomic.AddInt64(&errorCount, 1) }
アプリケーションの統計情報を保持する原子的に更新される変数を宣言します。
8.7 環境変数
[編集]var ( environment string port string ) func init() { environment = os.Getenv("ENV") if environment == "" { environment = "development" } port = os.Getenv("PORT") if port == "" { port = "8080" } }
環境変数から設定を読み込む変数を宣言します。
8.8 定数のようなパッケージレベル変数
[編集]var ( // これらは事実上定数だが、計算結果なので定数として宣言できない MaxSafeInteger = int64(1)<<53 - 1 DefaultTimeout = 30 * time.Second )
計算が必要でconstとして宣言できない「定数同様の値」を定義できます。
8.9 スレッドセーフな初期化
[編集]var ( config *Config configLock sync.RWMutex ) func GetConfig() *Config { configLock.RLock() if config != nil { defer configLock.RUnlock() return config } configLock.RUnlock() configLock.Lock() defer configLock.Unlock() if config == nil { config = loadConfigFromFile() } return config }
ミューテックスを使用して、スレッドセーフな遅延初期化を実装できます。
8.10 テスト用の変数
[編集]var ( // テスト時に差し替え可能 timeNow = time.Now randInt = rand.Int ) func generateID() string { now := timeNow() random := randInt() return fmt.Sprintf("%d-%d", now.Unix(), random) }
テスト時に差し替え可能な関数変数を宣言します。
9. var と型のユースケース
[編集]9.1 インターフェースの実装確認
[編集]var _ io.Reader = (*MyReader)(nil) var _ io.Writer = (*MyWriter)(nil)
コンパイル時にインターフェースの実装を確認するパターンです。
9.2 埋め込みインターフェースと構造体
[編集]type Handler struct { // 埋め込みインターフェース var http.Handler // 追加フィールド Logger *log.Logger }
構造体内にインターフェースを埋め込むことができます(通常はキーワードなしで書きます)。
9.3 関数型変数
[編集]var ( // HTTPハンドラー関数の型 homeHandler = func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Home Page") } // 計算関数の型 calculator = func(a, b int) int { return a + b } )
関数型の変数を宣言して関数値を代入できます。
10. var と並行処理パターン
[編集]10.1 ゴルーチンの通信チャネル
[編集]var ( tasks = make(chan Task, 100) results = make(chan Result, 100) errors = make(chan error, 100) done = make(chan struct{}) ) func startWorkers(n int) { for i := 0; i < n; i++ { go worker(tasks, results, errors) } }
ゴルーチン間の通信に使用するチャネルを宣言します。
10.2 コンテキスト変数
[編集]var ( rootCtx context.Context rootCtxCancel context.CancelFunc ) func init() { rootCtx, rootCtxCancel = context.WithCancel(context.Background()) } func cleanup() { rootCtxCancel() }
アプリケーション全体で使用するルートコンテキストを宣言します。
10.3 同期プリミティブ
[編集]var ( mu sync.Mutex rwmu sync.RWMutex once sync.Once wg sync.WaitGroup cond = sync.NewCond(&sync.Mutex{}) )
並行処理のための同期プリミティブを宣言します。
10.4 アトミック変数
[編集]var ( counter int64 isShutdown int32 ) func increment() int64 { return atomic.AddInt64(&counter, 1) } func shutdown() { atomic.StoreInt32(&isShutdown, 1) } func isActive() bool { return atomic.LoadInt32(&isShutdown) == 0 }
アトミックな操作が必要な変数を宣言します。
まとめ
[編集]Goのvarキーワードは変数宣言のための基本的なキーワードであり、さまざまな状況で使用されます:
- 基本的な変数宣言(型指定あり・なし)
- パッケージレベルとブロックスコープでの宣言
- 様々な型(基本型、複合型、カスタム型)の変数宣言
- 他のキーワード(const, func, go, defer, type, range, switch, if)との組み合わせ
- 特殊パターン(シャドウイング、ブランク識別子、nil代入)
- 実践的なユースケース(フラグ変数、グローバル設定、シングルトン、依存関係注入、キャッシュ)
- 型に関連するユースケース(インターフェース実装確認、関数型変数)
- 並行処理パターン(チャネル、コンテキスト、同期プリミティブ、アトミック変数)
varキーワードの適切な使用法を理解することで、より読みやすく保守性の高いGoプログラムを書くことができます。varは単なる変数宣言の手段以上のものであり、Goの設計哲学とイディオムを反映しています。適切なコンテキストでvarを使用するか短縮宣言(:=)を使用するかを理解することは、効果的なGoプログラミングの重要な側面です。