Skip to content

Go 変数

変数は値を保存するための記憶領域で、実行時に保存する値を動的に変更できます。変数を宣言するたびに、対応する型の値を保存するためのメモリが割り当てられます。詳細は リファレンスマニュアル - 変数 をご覧ください。

宣言

Go での型宣言は後置されます。変数の宣言には var キーワードが使用され、形式は var 変数名 型名 です。変数名の命名規則は識別子の命名規則に従う必要があります。

go
var intNum int
var str string
var char byte

複数の同じ型の変数を宣言する場合は、型を 1 回だけ記述できます。

go
var numA, numB, numC int

複数の異なる型の変数を宣言する場合は、() で囲むことができます。() は複数存在できます。

go
var (
  name    string
  age     int
  address string
)

var (
  school string
  class int
)

変数が宣言されただけで代入されていない場合、変数が保存する値は対応する型のゼロ値になります。

代入

代入には演算子 = が使用されます。

go
var name string
name = "jack"

宣言時に直接代入することもできます。

go
var name string = "jack"

または次のようにも書けます。

go
var name string
var age int
name, age = "jack", 1

2 番目の方法は毎回型を指定する必要があるため、公式が提供する構文糖衣である短変数初期化を使用できます。これにより var キーワードと後置型を省略でき、どの型になるかはコンパイラに推論させます。

go
name := "jack" // 文字列型の変数

型を指定しなくてもよいですが、後続の代入では型は一致している必要があります。以下のコードはコンパイルできません。

a := 1
a = "1"

また、短変数初期化では nil を使用できません。nil はどの型にも属さないため、コンパイラが型を推論できないからです。

go
name := nil // コンパイルできません

短変数宣言はバッチ初期化できます。

go
name, age := "jack", 1

短変数宣言は既存の変数には使用できません。

go
// 間違いの例
var a int
a := 1

// 間違いの例
a := 1
a := 2

ただし、例外として、古い変数に代入しながら新しい変数を宣言する場合は可能です。

go
a := 1
a, b := 2, 2

このコードはコンパイルできます。変数 a は再代入され、b は新規宣言されます。

Go 言語には、関数内の変数は必ず使用されなければならないというルールがあります。以下のコードは変数を宣言しているだけで使用していません。

go
func main() {
  a := 1
}

コンパイル時にエラーが発生し、変数が宣言されているが使用されていないと通知されます。

a declared and not used

このルールは関数内の変数にのみ適用され、関数外のパッケージレベル変数には制限がありません。以下のコードはコンパイルできます。

go
var a = 1

func main() {

}

匿名

アンダースコアを使用して、特定の変数が不要であることを示せます。

go
Open(name string) (*File, error)

例えば os.Open 関数は 2 つの戻り値を持ちますが、1 つ目だけが必要で 2 つ目が不要な場合は、次のように書けます。

go
file, _ := os.Open("readme.txt")

未使用の変数はコンパイルできません。特定の変数が不要な場合は、アンダースコア _ で置き換えます。

交換

Go で 2 つの変数の値を交換する場合、ポインタを使用する必要はありません。代入演算子を使用して直接交換できます。構文は非常に直感的です。

go
num1, num2 := 25, 36
num1, num2 = num2, num1

3 つの変数でも同様です。

go
num1, num2, num3 := 25, 36, 49
num1, num2, num3  = num3, num2, num1

以下のコードを考えてみてください。これはフィボナッチ数列を計算するコードの一部です。計算後の 3 つの変数の値はそれぞれいくつでしょうか。

go
a, b, c := 0, 1, 1
a, b, c = b, c, a+b

答えは

1 1 1

なぜ

1 1 2

ではないのか疑問に思うかもしれません。a は b の値に代入されたのに、なぜ a+b の結果は 1 のままなのでしょうか。Go では複数の変数を代入する場合、値を先に計算してから代入します。左から右に計算するわけではありません。

go
a, b, c = b, c, a+b

これは次のように展開されると思うかもしれません。

go
a = b
b = c
c = a + b

しかし実際には、a、b、c の 3 つの値をそれぞれ計算してから代入します。つまり、次のコードと同じです。

go
a, b, c = 1, 1, 0+1

関数呼び出しが関係すると、この効果がより明確になります。2 つの数値の合計を計算する sum 関数があるとします。

go
func sum(a, b int) int {
  return a + b
}

関数を使用して 2 つの数値を加算します。

go
a, b, c := 0, 1, 1
a, b, c = b, c, sum(a, b)

結果は変わりません。sum 関数の戻り値を計算する際、引数は依然として 0 と 1 です。

1 1 1

したがって、コードは次のように分けて書くべきです。

go
a, b = b, c
c = a + b

比較

変数の比較には前提条件があります。変数間の型は同じでなければなりません。Go には暗黙の型変換が存在しないため、以下のコードはコンパイルできません。

go
func main() {
  var a uint64
  var b int64
  fmt.Println(a == b)
}

コンパイラは両者の型が異なると通知します。

invalid operation: a == b (mismatched types uint64 and int64)

したがって、明示的な型変換を使用する必要があります。

go
func main() {
  var a uint64
  var b int64
  fmt.Println(int64(a) == b)
}

ジェネリックが導入される前、Go の組み込み minmax 関数は浮動小数点数のみをサポートしていました。バージョン 1.21 で、ようやくこれらの組み込み関数がジェネリックで書き直されました。現在では min 関数を使用して最小値を比較できます。

go
minVal := min(1, 2, -1, 1.2)

max 関数を使用して最大値を比較します。

go
maxVal := max(100, 22, -1, 1.12)

これらのパラメータはすべての比較可能な型をサポートしています。Go の比較可能な型は以下の通りです。

  • 布尔型
  • 数値型
  • 文字列型
  • ポインタ型
  • チャネル型(等価性の判断のみサポート)
  • 要素が比較可能な型の配列(スライスは比較できません)(等価性の判断のみサポート)(同じ長さの配列間の比較のみサポート。配列の長さも型の一部であり、異なる型は比較できません)
  • フィールド型がすべて比較可能な型の構造体(等価性の判断のみサポート)

これらに加えて、標準ライブラリ cmp をインポートして判断することもできますが、順序のある型のパラメータのみをサポートしています。Go の組み込みの順序のある型は数値と文字列のみです。

go
import "cmp"

func main() {
  cmp.Compare(1, 2)
  cmp.Less(1, 2)
}

コードブロック

関数内部では、波括弧を使用してコードブロックを確立できます。コードブロック間の変数のスコープは相互に独立しています。例えば、以下のコード。

go
func main() {
  a := 1

  {
    a := 2
    fmt.Println(a)
  }

  {
    a := 3
    fmt.Println(a)
  }
  fmt.Println(a)
}

出力は以下のようになります。

2
3
1

ブロック間の変数は相互に独立しており、干渉を受けず、アクセスできませんが、親ブロックの影響を受けます。

go
func main() {
  a := 1

  {
    a := 2
    fmt.Println(a)
  }

  {
    fmt.Println(a)
  }
  fmt.Println(a)
}

出力は以下のようになります。

2
1
1

Golang by www.golangdev.cn edit