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

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

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

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

スポンサーリンク

背景

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

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

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

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

演算子の優先順位(Operator precedence)

単項演算子は最も高い優先順位を持つ。++-- 演算子は式ではなく文を構成するため、演算子の階層の外にある。その結果、文 *p++(*p)++ と同じになる。

二項演算子には5つの優先順位レベルがある。乗算演算子が最も強く結合し、続いて加算演算子、比較演算子、&&(論理AND)、最後に ||(論理OR)の順である:

優先順位      演算子
    5             *  /  %  <<  >>  &  &^
    4             +  -  |  ^
    3             ==  !=  <  <=  >  >=
    2             &&
    1             ||

同じ優先順位の二項演算子は左から右へ結合する。たとえば、x / y * z(x / y) * z と同じである。

+x                         // x
42 + a - b                 // (42 + a) - b
23 + 3*x[i]                // 23 + (3 * x[i])
x <= f()                   // x <= f()
^a >> b                    // (^a) >> b
f() || g()                 // f() || g()
x == y+1 && <-chanInt > 0  // (x == (y+1)) && ((<-chanInt) > 0)

解説

優先順位表の読み方

数字が大きいほど優先順位が高い(先に計算される)ということです。算数の「掛け算は足し算より先」と同じ考え方ですね。

23 + 3*x[i]
// ステップ1: x[i] を評価(インデックスアクセスは演算子より先)
// ステップ2: 3 * x[i]  (優先順位5)
// ステップ3: 23 + 結果  (優先順位4)

単項演算子は最強

単項演算子(+-!^*&<-)は、どの二項演算子よりも優先順位が高いです。

^a >> b    // (^a) >> b であって、^(a >> b) ではない
-x + y     // (-x) + y であって、-(x + y) ではない

^a はビット反転(NOT)で、まず a のビットを反転してから b だけ右シフトする、という意味になります。

++ と -- は「文」であって「式」ではない

C言語や JavaScript に慣れている方にとって、これは Go の大きな特徴です。

// C/JavaScript では式として使える
y = x++     // C では OK

// Go では文としてしか使えない
x++         // OK(文として単独で使う)
y = x++     // コンパイルエラー! x++ は値を返さない

だから *p++ は次のように解釈されます。

*p++
// ステップ1: *p でポインタをデリファレンス
// ステップ2: その値をインクリメント
// つまり (*p)++ と同じ

C言語では *(p++) と解釈される可能性がありますが、Go では ++ が式ではないのでそうなりません。この設計によって i++ + ++j のようなわかりにくいコードが原理的に書けなくなっています。

左から右への結合

同じ優先順位の演算子が並んだら、左から右の順で結合します。

x / y * z    // (x / y) * z
42 + a - b   // (42 + a) - b

これは算数の感覚と同じなので、自然に読めると思います。

複雑な式の読み解き方

原文の最後の例が一番複雑なので、丁寧に分解してみましょう。

x == y+1 && <-chanInt > 0

ステップ1:単項演算子を先に処理

<-chanInt → チャネルから受信(単項演算子、最優先)

ステップ2:優先順位5(乗算系)

該当なし。

ステップ3:優先順位4(加算系)

y+1 → 加算

ステップ4:優先順位3(比較系)

x == (y+1)(<-chanInt) > 0 → 2つの比較

ステップ5:優先順位2(論理AND)

(x == (y+1)) && ((<-chanInt) > 0) → 全体の結合

結果:

(x == (y+1)) && ((<-chanInt) > 0)

実用的なアドバイス

優先順位を暗記する必要はありません。大事なのは2つだけです。

1. 迷ったら括弧をつける

// 読みにくい
result := a & b == 0

// 読みやすい
result := (a & b) == 0

括弧をつけることで、自分の意図を明示できますし、読む人も安心できます。

2. Go のビット演算子は C と優先順位が違う

C 言語では &| は比較演算子より優先順位が低いですが、Go では乗算系(優先順位5)に分類されています。C から来た人は特に注意が必要です。

// Go では
a & b == 0   // (a & b) == 0   ← & が先(優先順位5 > 3)

// C では
a & b == 0   // a & (b == 0)   ← == が先(C の & は == より低い)

Go のほうが直感的な順序になっていますが、C の癖がある人は混乱しやすいので、やはり括弧を書くのが安全です。

おわりに 

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

よっしー
よっしー

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

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

コメント

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