
こんにちは。よっしーです(^^)
本日は、Go言語の言語仕様について解説しています。
背景
Go言語を学び始めて、公式の「The Go Programming Language Specification(言語仕様書)」を開いてみたものの、「英語で書かれていて読むのが大変…」「専門用語ばかりで何を言っているのかわからない…」と感じたことはありませんか? 実は、多くのGo初心者が同じ壁にぶつかっています。
言語仕様書は、Go言語の「正式な取扱説明書」のような存在です。プログラミング言語がどのように動くのか、どんなルールで書くべきなのかが詳しく書かれていますが、その分、初めて読む人には難しく感じられるのも事実です。
そこでこの記事では、言語仕様書の導入部分を丁寧な日本語訳とともに、初心者の方でも理解しやすい補足説明を加えてお届けします。「強く型付けされている」「ガベージコレクション」「並行プログラミング」といった専門用語も、具体例を交えながらわかりやすく解説していきます。
言語仕様書は難しそうに見えますが、一つひとつの概念を丁寧に読み解いていけば、必ず理解できます。一緒に、Go言語の基礎をしっかり学んでいきましょう!
Operators and punctuation(演算子と句読点)
以下の文字列は、演算子(代入演算子を含む)と句読点を表します[Go 1.18]:
+ & += &= && == != ( )
- | -= |= || < <= [ ]
* ^ *= ^= <- > >= { }
/ << /= <<= ++ = := , ;
% >> %= >>= -- ! ... . :
&^ &^= ~
解説
演算子と句読点とは何か?
演算子は、値に対して操作を行う記号です。句読点は、コードの構造を示す記号です。これらはGoプログラムを書く上で欠かせない基本要素です。
たとえ話: 数学の式「3 + 5 = 8」で、「+」が演算子、「=」も演算子です。同じように、プログラミングでも演算子を使って計算や操作を行います。
1. 算術演算子(Arithmetic operators)
数値の計算に使う演算子です。
+ (加算)
package main
import "fmt"
func main() {
// 数値の加算
result := 10 + 5
fmt.Println(result) // 15
// 文字列の連結
message := "Hello" + " " + "World"
fmt.Println(message) // Hello World
// 浮動小数点
pi := 3.14 + 0.00159
fmt.Println(pi) // 3.14159
}
- (減算・符号反転)
package main
import "fmt"
func main() {
// 減算
result := 10 - 5
fmt.Println(result) // 5
// 負の数(単項演算子)
negative := -42
fmt.Println(negative) // -42
// 正の数に変換
positive := -(-10)
fmt.Println(positive) // 10
}
* (乗算)
package main
import "fmt"
func main() {
// 乗算
result := 10 * 5
fmt.Println(result) // 50
// ポインタの宣言(別の意味でも使う)
var x int = 42
var ptr *int = &x // *intはintのポインタ型
fmt.Println(*ptr) // 42 (ポインタの参照外し)
}
/ (除算)
package main
import "fmt"
func main() {
// 整数同士の除算は整数部分のみ
result1 := 10 / 3
fmt.Println(result1) // 3 (小数部分は切り捨て)
// 浮動小数点の除算
result2 := 10.0 / 3.0
fmt.Println(result2) // 3.3333...
// 型変換して浮動小数点除算
a := 10
b := 3
result3 := float64(a) / float64(b)
fmt.Println(result3) // 3.3333...
}
% (剰余・モジュロ)
package main
import "fmt"
func main() {
// 剰余(割り算の余り)
result := 10 % 3
fmt.Println(result) // 1
// 偶数・奇数の判定
num := 7
if num%2 == 0 {
fmt.Println("偶数")
} else {
fmt.Println("奇数") // こちらが出力される
}
// 負の数の剰余
fmt.Println(-10 % 3) // -1
fmt.Println(10 % -3) // 1
fmt.Println(-10 % -3) // -1
}
2. 比較演算子(Comparison operators)
値を比較して真偽値(true/false)を返します。
== (等しい)
package main
import "fmt"
func main() {
// 数値の比較
fmt.Println(10 == 10) // true
fmt.Println(10 == 5) // false
// 文字列の比較
fmt.Println("Hello" == "Hello") // true
fmt.Println("Hello" == "World") // false
// 真偽値の比較
fmt.Println(true == true) // true
fmt.Println(true == false) // false
}
!= (等しくない)
package main
import "fmt"
func main() {
fmt.Println(10 != 5) // true
fmt.Println(10 != 10) // false
fmt.Println("A" != "B") // true
// エラーチェックでよく使う
value, err := someFunction()
if err != nil {
fmt.Println("エラーが発生しました")
}
}
< (より小さい)
package main
import "fmt"
func main() {
fmt.Println(5 < 10) // true
fmt.Println(10 < 10) // false
fmt.Println(15 < 10) // false
// 年齢チェック
age := 17
if age < 18 {
fmt.Println("未成年です")
}
}
<= (以下)
package main
import "fmt"
func main() {
fmt.Println(5 <= 10) // true
fmt.Println(10 <= 10) // true (等しい場合もtrue)
fmt.Println(15 <= 10) // false
}
> (より大きい)
package main
import "fmt"
func main() {
fmt.Println(15 > 10) // true
fmt.Println(10 > 10) // false
fmt.Println(5 > 10) // false
}
>= (以上)
package main
import "fmt"
func main() {
fmt.Println(15 >= 10) // true
fmt.Println(10 >= 10) // true
fmt.Println(5 >= 10) // false
// 成人チェック
age := 20
if age >= 18 {
fmt.Println("成人です")
}
}
3. 論理演算子(Logical operators)
真偽値を組み合わせる演算子です。
&& (論理積・AND)
両方がtrueの場合のみtrue
package main
import "fmt"
func main() {
// 両方trueならtrue
fmt.Println(true && true) // true
fmt.Println(true && false) // false
fmt.Println(false && true) // false
fmt.Println(false && false) // false
// 実用例: 範囲チェック
age := 25
if age >= 18 && age < 65 {
fmt.Println("成人労働者年齢")
}
// 短絡評価(左がfalseなら右は評価されない)
x := 0
if x != 0 && 10/x > 2 { // x!=0がfalseなので10/xは実行されない
fmt.Println("OK")
}
}
|| (論理和・OR)
どちらか一方でもtrueならtrue
package main
import "fmt"
func main() {
// どちらかtrueならtrue
fmt.Println(true || true) // true
fmt.Println(true || false) // true
fmt.Println(false || true) // true
fmt.Println(false || false) // false
// 実用例: 休日チェック
day := "土曜日"
if day == "土曜日" || day == "日曜日" {
fmt.Println("週末です")
}
// 短絡評価(左がtrueなら右は評価されない)
x := 10
if x == 10 || expensive() { // x==10がtrueなのでexpensive()は呼ばれない
fmt.Println("OK")
}
}
func expensive() bool {
fmt.Println("重い処理")
return true
}
! (論理否定・NOT)
真偽値を反転します。
package main
import "fmt"
func main() {
fmt.Println(!true) // false
fmt.Println(!false) // true
// 実用例
isLoggedIn := false
if !isLoggedIn {
fmt.Println("ログインしてください")
}
// 二重否定
value := true
fmt.Println(!!value) // true
}
4. ビット演算子(Bitwise operators)
ビット単位で操作する演算子です。
& (ビット積・AND)
package main
import "fmt"
func main() {
// ビット単位のAND
// 1010 (10)
// & 1100 (12)
// ------
// 1000 (8)
result := 10 & 12
fmt.Println(result) // 8
// フラグチェック
const (
FlagRead = 1 << 0 // 0001
FlagWrite = 1 << 1 // 0010
FlagExecute = 1 << 2 // 0100
)
permissions := FlagRead | FlagWrite // 0011
if permissions&FlagWrite != 0 {
fmt.Println("書き込み権限あり")
}
// アドレス演算子(別の意味)
x := 42
ptr := &x // xのアドレスを取得
fmt.Printf("アドレス: %p\n", ptr)
}
| (ビット和・OR)
package main
import "fmt"
func main() {
// ビット単位のOR
// 1010 (10)
// | 1100 (12)
// ------
// 1110 (14)
result := 10 | 12
fmt.Println(result) // 14
// フラグの組み合わせ
const (
FlagRead = 1 // 001
FlagWrite = 2 // 010
FlagExec = 4 // 100
)
permissions := FlagRead | FlagWrite // 011 (読み書き可能)
fmt.Println(permissions) // 3
}
^ (ビット排他的論理和・XOR)
package main
import "fmt"
func main() {
// ビット単位のXOR
// 1010 (10)
// ^ 1100 (12)
// ------
// 0110 (6)
result := 10 ^ 12
fmt.Println(result) // 6
// ビット反転(単項演算子として)
x := 10 // 0000...1010
y := ^x // 1111...0101 (全ビット反転)
fmt.Println(y) // -11
// XORの特性: 同じ値で2回XORすると元に戻る
original := 42
key := 123
encrypted := original ^ key
decrypted := encrypted ^ key
fmt.Println(decrypted) // 42 (元に戻る)
}
&^ (ビットクリア・AND NOT)
Go特有の演算子です。
package main
import "fmt"
func main() {
// ビットクリア
// 1010 (10)
// &^1100 (12)
// ------
// 0010 (2)
// 右側が1のビットを左側から0にする
result := 10 &^ 12
fmt.Println(result) // 2
// フラグの削除
const (
FlagRead = 1 // 001
FlagWrite = 2 // 010
FlagExec = 4 // 100
)
permissions := FlagRead | FlagWrite | FlagExec // 111
permissions = permissions &^ FlagWrite // 101 (書き込み権限を削除)
fmt.Println(permissions) // 5
}
<< (左シフト)
package main
import "fmt"
func main() {
// 左シフト(ビットを左に移動、2のn乗を掛ける)
result := 5 << 2
// 0101 → 10100
// 5 * 2^2 = 20
fmt.Println(result) // 20
// 2のべき乗を簡単に作る
fmt.Println(1 << 0) // 1
fmt.Println(1 << 1) // 2
fmt.Println(1 << 2) // 4
fmt.Println(1 << 3) // 8
fmt.Println(1 << 10) // 1024
}
>> (右シフト)
package main
import "fmt"
func main() {
// 右シフト(ビットを右に移動、2のn乗で割る)
result := 20 >> 2
// 10100 → 00101
// 20 / 2^2 = 5
fmt.Println(result) // 5
// 整数の2での除算
fmt.Println(100 >> 1) // 50 (100 / 2)
fmt.Println(100 >> 2) // 25 (100 / 4)
fmt.Println(100 >> 3) // 12 (100 / 8)
}
5. 代入演算子(Assignment operators)
= (代入)
package main
func main() {
// 基本的な代入
var x int = 10
// 複数同時代入
a, b := 1, 2
// 構造体の代入
type Point struct {
X, Y int
}
p := Point{X: 10, Y: 20}
}
:= (短縮変数宣言)
package main
func main() {
// varを省略した宣言と代入
name := "太郎" // var name string = "太郎" と同じ
age := 25 // var age int = 25 と同じ
// 複数変数
x, y := 10, 20
// 既存の変数と組み合わせ(少なくとも1つは新しい変数が必要)
value, err := someFunction()
value, err2 := anotherFunction() // valueは既存、err2は新規
}
複合代入演算子
package main
import "fmt"
func main() {
x := 10
// 加算代入
x += 5 // x = x + 5
fmt.Println(x) // 15
// 減算代入
x -= 3 // x = x - 3
fmt.Println(x) // 12
// 乗算代入
x *= 2 // x = x * 2
fmt.Println(x) // 24
// 除算代入
x /= 4 // x = x / 4
fmt.Println(x) // 6
// 剰余代入
x %= 4 // x = x % 4
fmt.Println(x) // 2
// ビット演算代入
x &= 3 // x = x & 3
x |= 5 // x = x | 5
x ^= 2 // x = x ^ 2
x <<= 1 // x = x << 1
x >>= 1 // x = x >> 1
x &^= 1 // x = x &^ 1
}
6. インクリメント・デクリメント
++ (インクリメント)
package main
import "fmt"
func main() {
x := 10
x++ // x = x + 1
fmt.Println(x) // 11
// ループでよく使う
for i := 0; i < 5; i++ {
fmt.Println(i)
}
// 注意: Goでは前置インクリメントは使えない
// ++x // エラー!
// 注意: 式の一部としては使えない
// y := x++ // エラー!
// 正しくは:
x++
y := x
}
-- (デクリメント)
package main
import "fmt"
func main() {
x := 10
x-- // x = x - 1
fmt.Println(x) // 9
// カウントダウン
count := 5
for count > 0 {
fmt.Println(count)
count--
}
}
7. チャネル演算子
<- (チャネル送受信)
package main
import "fmt"
func main() {
// チャネルの作成
ch := make(chan int)
// ゴルーチンで送信
go func() {
ch <- 42 // チャネルに値を送信
}()
// 受信
value := <-ch // チャネルから値を受信
fmt.Println(value) // 42
// 受信専用チャネル
go func(ch <-chan int) {
val := <-ch
fmt.Println(val)
}(ch)
// 送信専用チャネル
go func(ch chan<- int) {
ch <- 100
}(ch)
}
8. 句読点(Punctuation)
() (丸括弧)
package main
func main() {
// 関数呼び出し
result := add(10, 20)
// グループ化
x := (10 + 5) * 2 // 30
// 型変換
f := float64(42)
// 制御文
if (x > 10) {
// ...
}
}
func add(a, b int) int {
return a + b
}
[] (角括弧)
package main
func main() {
// 配列の宣言
var arr [5]int
// スライスの宣言
slice := []int{1, 2, 3}
// インデックスアクセス
value := slice[0]
// スライス操作
subSlice := slice[1:3] // [2, 3]
}
{} (波括弧)
package main
func main() { // ブロックの開始
// 複合リテラル
point := struct {
X, Y int
}{10, 20}
// マップ
m := map[string]int{
"a": 1,
"b": 2,
}
// スライス
s := []int{1, 2, 3}
} // ブロックの終了
, (カンマ)
package main
func main() {
// 要素の区切り
slice := []int{1, 2, 3}
// 複数変数の宣言
var a, b, c int
// 関数の引数
result := add(10, 20)
// 複数の戻り値
value, err := someFunc()
}
; (セミコロン)
package main
func main() {
// 通常は省略(自動挿入)
x := 10
y := 20
// 明示的に書くことも可能(非推奨)
a := 1; b := 2
// forループでは必須
for i := 0; i < 10; i++ {
// ...
}
}
. (ドット)
package main
import "fmt"
type Person struct {
Name string
}
func main() {
// パッケージのメンバーアクセス
fmt.Println("Hello")
// 構造体のフィールドアクセス
p := Person{Name: "太郎"}
name := p.Name
// メソッド呼び出し
p.SayHello()
}
func (p Person) SayHello() {
fmt.Println("Hello,", p.Name)
}
: (コロン)
package main
func main() {
// 短縮変数宣言
x := 10
// スライスの範囲指定
slice := []int{1, 2, 3, 4, 5}
sub := slice[1:3] // [2, 3]
// 構造体リテラルのフィールド名
type Point struct {
X, Y int
}
p := Point{X: 10, Y: 20}
// ラベル
Loop:
for {
break Loop
}
}
... (省略記号)
package main
import "fmt"
func main() {
// 可変長引数
sum := add(1, 2, 3, 4, 5)
fmt.Println(sum)
// スライスの展開
numbers := []int{1, 2, 3}
sum2 := add(numbers...)
fmt.Println(sum2)
// 配列リテラルの長さ自動計算
arr := [...]int{1, 2, 3, 4, 5} // 長さ5の配列
}
func add(numbers ...int) int {
total := 0
for _, n := range numbers {
total += n
}
return total
}
~ (型制約の近似)[Go 1.18]
ジェネリクスで使用されます。
package main
import "fmt"
// 型制約で使用
type Integer interface {
~int | ~int8 | ~int16 | ~int32 | ~int64
}
func Sum[T Integer](values []T) T {
var total T
for _, v := range values {
total += v
}
return total
}
type MyInt int
func main() {
// ~int があるのでMyInt型も使える
numbers := []MyInt{1, 2, 3}
result := Sum(numbers)
fmt.Println(result) // 6
}
まとめ: 演算子と句読点で覚えておくべきこと
演算子の優先順位(高い→低い)
*,/,%,<<,>>,&,&^+,-,|,^==,!=,<,<=,>,>=&&||
package main
import "fmt"
func main() {
// 優先順位の例
result := 10 + 5 * 2 // 20 (5*2が先に計算される)
// 括弧で優先順位を変更
result2 := (10 + 5) * 2 // 30
fmt.Println(result, result2)
}
実用的なアドバイス
package main
import "fmt"
func main() {
// よく使う演算子の組み合わせ
// 算術
x := 10 + 5
x *= 2
x++
// 比較
if x > 20 && x < 50 {
fmt.Println("範囲内")
}
// ビット演算(フラグ管理)
const (
FlagA = 1 << 0
FlagB = 1 << 1
FlagC = 1 << 2
)
flags := FlagA | FlagB
if flags&FlagA != 0 {
fmt.Println("FlagAが立っている")
}
// チャネル
ch := make(chan int)
go func() {
ch <- 42
}()
value := <-ch
fmt.Println(value)
}
演算子と句読点は、Goプログラムの基本的な構成要素です。これらを組み合わせることで、複雑なロジックを表現できます!
おわりに
本日は、Go言語の言語仕様について解説しました。

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

コメント