🐐
「Go初心者がハマる!:=と=の違いと複数戻り値・スコープの罠を一発理解」
Go言語では、変数の宣言と代入に「=」と「:=」という2種類の演算子が存在します。特に複数戻り値を受け取る場合や、グローバル変数・ローカル変数の扱いで混乱しやすいため、ポイントを整理します。
基本(こんなのは当たり前だー‼︎)
当たり前すぎて恐縮ですが、我慢して聞いてください。
1. 「=」と「:=」の違い
:=(短縮宣言)
- 新しい変数の宣言と初期化を同時に行う。
- 関数内でのみ使用可能。
- 型は右辺の値から自動推論される。
go
num := 10 *// int型のnumを新規宣言し、10を代入*
=(代入)
- 既に宣言されている変数に値を再代入する。
- 新しい変数の宣言は行わない。
- グローバル変数や関数スコープ内の既存変数に値をセットする場合に使う。
go
var num int
num = 20 *// 既存のnumに20を代入*
2. 複数戻り値と「:=」「=」の使い分け
Goでは複数の戻り値を返す関数が多用されます。
このとき、戻り値を受け取る変数のうち宣言されている変数と、未宣言の変数が存在するときどうなるのさ?
例1:全て未宣言の場合
go
a, b := someFunc()
両方とも新規宣言。
例2:一部が既存の場合
go
var a int
a, b := someFunc()
aは再代入、bは新規宣言。
例3:全て既存の場合
go
var a, b int
a, b = someFunc()
両方とも再代入。
3. グローバル変数とローカル変数のシャドーイング
『なんや、:=
ってめっちゃ便利やん。未宣言の変数に出会ったらガンガン使っちゃお!』と思ったそこのあなた、ちょい甘いです。
グローバルで宣言済みの変数を、関数内で:=
しちゃうと思ってもみない挙動になります。
NG例(グローバル変数が更新されない)
go
var DB *sql.DB
func InitDB() {
DB, err := sql.Open("postgres", ...)
// ここでDBはローカル変数として新規宣言され、グローバル変数DBは更新されない
}
OK例(グローバル変数を更新する)
go
var DB *sql.DB
func InitDB() {
var err error
DB, err = sql.Open("postgres", ...)
// ここでDBはグローバル変数、errはローカル変数
}
【まとめ】スコープ内での「:=」の挙動
- 同じスコープ内で既に宣言されている変数には「:=」で新たにローカル変数が作られることはありません。
- ただし、外側スコープ(グローバルなど)で宣言されている場合は、関数内で「:=」を使うとローカル変数として新たに宣言されてシャドーイングされる。
変数の状態 | := の挙動 |
---|---|
未宣言 | 新規宣言+初期化 |
同じスコープで宣言済 | 再代入(新規宣言はされない) |
外側スコープで宣言済 | 新たにローカル変数としてシャドーイングされる |
最後に(ベストプラクティス)
- グローバル変数を関数内で更新したい場合は、関数内で新たに同名の変数を宣言しないこと。
- 複数戻り値で一部が未宣言の場合、
:=
でまとめて宣言・代入できるが、スコープに注意。 - 関数内ですでに宣言されている変数には「:=」で新たにローカル変数は作られない。
Discussion