Go言語入門:言語仕様 -Vol.55-

スポンサーリンク
Go言語入門:言語仕様 -Vol.55- 用語解説
Go言語入門:言語仕様 -Vol.55-
この記事は約6分で読めます。
よっしー
よっしー

こんにちは。よっしーです(^^)

本日は、Go言語の言語仕様について解説しています。

スポンサーリンク

背景

Go言語を学び始めて、公式の「The Go Programming Language Specification(言語仕様書)」を開いてみたものの、「英語で書かれていて読むのが大変…」「専門用語ばかりで何を言っているのかわからない…」と感じたことはありませんか? 実は、多くのGo初心者が同じ壁にぶつかっています。

言語仕様書は、Go言語の「正式な取扱説明書」のような存在です。プログラミング言語がどのように動くのか、どんなルールで書くべきなのかが詳しく書かれていますが、その分、初めて読む人には難しく感じられるのも事実です。

そこでこの記事では、言語仕様書の導入部分を丁寧な日本語訳とともに、初心者の方でも理解しやすい補足説明を加えてお届けします。「強く型付けされている」「ガベージコレクション」「並行プログラミング」といった専門用語も、具体例を交えながらわかりやすく解説していきます。

言語仕様書は難しそうに見えますが、一つひとつの概念を丁寧に読み解いていけば、必ず理解できます。一緒に、Go言語の基礎をしっかり学んでいきましょう!

変数宣言(Variable declarations)

変数宣言は、1つ以上の変数を作成し、対応する識別子をそれらに束縛し、それぞれに型と初期値を与える。

VarDecl = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) .
VarSpec = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) .
var i int
var U, V, W float64
var k = 0
var x, y float32 = -1, -2
var (
	i       int
	u, v, s = 2.0, 3.0, "bar"
)
var re, im = complexSqrt(-1)
var _, found = entries[name]  // mapの検索; "found" のみに関心がある

式のリストが与えられた場合、変数は代入文の規則に従って式で初期化される。そうでない場合、各変数はそのゼロ値に初期化される。

型が指定されている場合、各変数にはその型が与えられる。そうでない場合、各変数には代入における対応する初期化値の型が与えられる。その値が型なし定数である場合、まず暗黙的にそのデフォルト型に変換される。型なし真偽値である場合、まず暗黙的に bool 型に変換される。事前宣言された識別子 nil は、明示的な型を持たない変数の初期化に使用することはできない。

var d = math.Sin(0.5)  // d は float64
var i = 42             // i は int
var t, ok = x.(T)      // t は T, ok は bool
var n = nil            // 不正

実装上の制限:コンパイラは、関数本体の中で宣言された変数が一度も使用されない場合、その宣言を不正とすることができる。


解説

変数宣言の基本

Goで変数を作るには var キーワードを使います。いくつか書き方のバリエーションがあるので、順番に見ていきましょう。

var i int          // 型だけ指定。値は自動的にゼロ値(int なら 0)になる
var k = 0          // 値だけ指定。型は値から自動的に推論される(int になる)
var x float32 = -1 // 型も値も指定。きっちり自分で決めるパターン

料理に例えると、変数宣言は「器を用意する」作業です。型は「器の種類」(お椀、お皿、コップ)、値は「中身」です。器だけ用意して中身を入れなければ、空っぽ(ゼロ値)になります。

複数の変数をまとめて宣言する

同じ型の変数をカンマで並べたり、()で囲んでグループにしたりできます。

// カンマで並べる
var U, V, W float64              // 3つとも float64 型、すべてゼロ値(0.0)

// 異なる型の変数をまとめたいときは () で囲む
var (
    i       int
    u, v, s = 2.0, 3.0, "bar"   // u=2.0, v=3.0, s="bar"
)

() を使ったグループ宣言は、パッケージレベル(関数の外)でよく使われます。関連する変数をひとまとめにできて見やすいですね。

ゼロ値とは

Goでは、値を指定しなかった変数には自動的にゼロ値が入ります。「未初期化で中身が不定」ということがないのは、Goの安全設計のひとつです。

var i int       // 0
var f float64   // 0.0
var s string    // ""(空文字列)
var b bool      // false
var p *int      // nil

型推論:型を書かなくてもいい場合

右辺に値を書けば、コンパイラが型を推論してくれます。

var d = math.Sin(0.5)  // math.Sin は float64 を返す → d は float64
var i = 42             // 42 は型なし定数 → デフォルト型の int になる

ここで「型なし定数」という言葉が出てきます。Goでは 42 のようなリテラルは、最初は特定の型に属しません。使われる文脈に応じて型が決まります。ただし var で型を省略した場合は、デフォルト型が自動的に選ばれます。

リテラルデフォルト型
42int
3.14float64
truebool
"hello"string

nil で初期化できないケース

nil は「何も指していない」を意味する特別な値ですが、型を省略した状態では使えません。

var n = nil  // コンパイルエラー!

なぜかというと、nil だけではコンパイラが型を推論できないからです。nil はポインタにもスライスにもmapにもなりえるので、「どの型の nil?」が決まりません。型を明示すればOKです。

var n *int = nil       // OK! *int 型の nil
var s []string = nil   // OK! []string 型の nil

関数の戻り値で複数の変数を初期化する

関数が複数の値を返す場合、それをまとめて受け取れます。

var re, im = complexSqrt(-1)      // 2つの戻り値を re と im で受け取る
var _, found = entries[name]       // 1つ目は捨てて、2つ目だけ使う

_(アンダースコア)は「この値は使わない」という意味の特別な識別子です。mapの検索結果で「値は要らないけど、キーが存在するかだけ知りたい」ときによく使うパターンですね。

未使用変数はエラーになる

原文の最後にある「実装上の制限」は、実質的にGoの標準コンパイラの挙動そのものです。関数の中で宣言した変数を一度も使わないと、コンパイルエラーになります。

func main() {
    var x int  // コンパイルエラー! x を使っていない
    fmt.Println("hello")
}

「せっかく宣言したのに使わないの? それバグじゃない?」とコンパイラが教えてくれているわけです。うっかりミスを防いでくれるありがたい仕組みですが、デバッグ中に一時的に変数を残したいときはちょっと煩わしいかもしれません。そんなときは _ に代入して回避できます。

func main() {
    var x int
    _ = x  // 「使った」ことになるのでエラーにならない
    fmt.Println("hello")
}

おわりに 

本日は、Go言語の言語仕様について解説しました。

よっしー
よっしー

何か質問や相談があれば、コメントをお願いします。また、エンジニア案件の相談にも随時対応していますので、お気軽にお問い合わせください。

それでは、また明日お会いしましょう(^^)

コメント

タイトルとURLをコピーしました