
こんにちは。よっしーです(^^)
本日は、Go言語の言語仕様について解説しています。
背景
Go言語を学び始めて、公式の「The Go Programming Language Specification(言語仕様書)」を開いてみたものの、「英語で書かれていて読むのが大変…」「専門用語ばかりで何を言っているのかわからない…」と感じたことはありませんか? 実は、多くのGo初心者が同じ壁にぶつかっています。
言語仕様書は、Go言語の「正式な取扱説明書」のような存在です。プログラミング言語がどのように動くのか、どんなルールで書くべきなのかが詳しく書かれていますが、その分、初めて読む人には難しく感じられるのも事実です。
そこでこの記事では、言語仕様書の導入部分を丁寧な日本語訳とともに、初心者の方でも理解しやすい補足説明を加えてお届けします。「強く型付けされている」「ガベージコレクション」「並行プログラミング」といった専門用語も、具体例を交えながらわかりやすく解説していきます。
言語仕様書は難しそうに見えますが、一つひとつの概念を丁寧に読み解いていけば、必ず理解できます。一緒に、Go言語の基礎をしっかり学んでいきましょう!
Imaginary literals(虚数リテラル)
虚数リテラルは、複素数定数の虚数部を表します。整数または浮動小数点リテラルの後に小文字のiが続きます。虚数リテラルの値は、対応する整数または浮動小数点リテラルの値に虚数単位i(√-1)を掛けたものです[Go 1.13]。
imaginary_lit = (decimal_digits | int_lit | float_lit) "i" .
後方互換性のため、10進数の数字(および場合によってはアンダースコア)のみで構成される虚数リテラルの整数部分は、先頭に0が付いていても、10進整数と見なされます。
0i
0123i // 後方互換性のため == 123i
0o123i // == 0o123 * 1i == 83i
0xabci // == 0xabc * 1i == 2748i
0.i
2.71828i
1.e+0i
6.67428e-11i
1E6i
.25i
.12345E+5i
0x1p-2i // == 0x1p-2 * 1i == 0.25i
解説
虚数とは何か?
虚数は、数学で「√-1」を表す特別な数です。通常の実数では「-1の平方根」は存在しませんが、虚数を使うことで表現できます。虚数単位をiと書き、i² = -1という性質を持ちます。
たとえ話: 普通の数直線(1次元)では表せない「もう一つの次元」の数です。実数が東西方向だとすると、虚数は南北方向のようなイメージです。
複素数とは?
複素数は、実数部と虚数部を組み合わせた数です。
複素数 = 実数部 + 虚数部
例: 3 + 4i
↑ ↑
実数部 虚数部
Goでは、complex64(32ビット)とcomplex128(64ビット)という型で複素数を扱えます。
1. 虚数リテラルの基本
虚数リテラルは、数値の後ろに小文字のiを付けるだけです。
整数ベースの虚数
package main
import "fmt"
func main() {
// 整数 + i
var img1 complex128 = 5i // 虚数部が5
var img2 complex128 = 42i // 虚数部が42
var img3 complex128 = 0i // 虚数部が0
fmt.Println(img1) // (0+5i)
fmt.Println(img2) // (0+42i)
fmt.Println(img3) // (0+0i)
// 型を確認
fmt.Printf("型: %T\n", img1) // complex128
}
浮動小数点ベースの虚数
package main
import "fmt"
func main() {
// 浮動小数点 + i
var img1 complex128 = 3.14i // 円周率の虚数版
var img2 complex128 = 2.71828i // 自然対数の底の虚数版
var img3 complex128 = 0.5i // 0.5の虚数版
var img4 complex128 = .25i // 小数点前の0を省略
fmt.Println(img1) // (0+3.14i)
fmt.Println(img2) // (0+2.71828i)
fmt.Println(img3) // (0+0.5i)
fmt.Println(img4) // (0+0.25i)
}
2. 複素数の作成
実数部と虚数部を組み合わせる
package main
import "fmt"
func main() {
// 実数部 + 虚数部
var c1 complex128 = 3 + 4i // 3 + 4i
var c2 complex128 = 5.5 + 2.3i // 5.5 + 2.3i
var c3 complex128 = 10 + 0i // 10 + 0i (実数と同じ)
var c4 complex128 = 0 + 7i // 0 + 7i (純虚数)
fmt.Println(c1) // (3+4i)
fmt.Println(c2) // (5.5+2.3i)
fmt.Println(c3) // (10+0i)
fmt.Println(c4) // (0+7i)
}
complex関数を使う方法
package main
import "fmt"
func main() {
// complex(実数部, 虚数部) で作成
c1 := complex(3, 4) // 3 + 4i
c2 := complex(5.5, 2.3) // 5.5 + 2.3i
fmt.Println(c1) // (3+4i)
fmt.Println(c2) // (5.5+2.3i)
// 実数部と虚数部を取り出す
real_part := real(c1) // 3
imag_part := imag(c1) // 4
fmt.Printf("実数部: %v, 虚数部: %v\n", real_part, imag_part)
}
3. 様々な表記法
10進数の虚数
package main
import "fmt"
func main() {
// 基本的な10進数
var a complex128 = 0i
var b complex128 = 123i
var c complex128 = 1_000_000i // アンダースコアも使える
fmt.Println(a, b, c)
}
8進数・16進数の虚数
package main
import "fmt"
func main() {
// 8進数ベース
var oct1 complex128 = 0o123i // 8進数の123 = 10進数の83
fmt.Println(oct1) // (0+83i)
// 16進数ベース
var hex1 complex128 = 0xabci // 16進数のabc = 10進数の2748
fmt.Println(hex1) // (0+2748i)
// 色の虚数版(あまり実用的ではないが可能)
var colorImg complex128 = 0xFFi
fmt.Println(colorImg) // (0+255i)
}
後方互換性: 0で始まる10進数
package main
import "fmt"
func main() {
// 注意: 0で始まる数字は通常8進数だが、
// 虚数リテラルの場合は後方互換性のため10進数として扱われる
var old complex128 = 0123i // 123i (10進数の123)
fmt.Println(old) // (0+123i) ← 8進数の83ではない!
// 明示的に8進数にするには 0o を使う
var oct complex128 = 0o123i
fmt.Println(oct) // (0+83i)
}
4. 浮動小数点の虚数
基本的な小数
package main
import "fmt"
func main() {
// 小数の虚数
var f1 complex128 = 0.i // 0.0i
var f2 complex128 = 3.14i // 3.14i
var f3 complex128 = .5i // 0.5i (小数点前の0を省略)
var f4 complex128 = 2.i // 2.0i
fmt.Println(f1, f2, f3, f4)
}
指数表記の虚数
package main
import "fmt"
func main() {
// 指数表記(科学的記数法)
var e1 complex128 = 1e6i // 1 × 10^6 = 1,000,000i
var e2 complex128 = 1.e+0i // 1 × 10^0 = 1i
var e3 complex128 = 6.67428e-11i // 重力定数の虚数版
var e4 complex128 = .12345E+5i // 0.12345 × 10^5 = 12345i
fmt.Println(e1) // (0+1e+06i)
fmt.Println(e2) // (0+1i)
fmt.Println(e3) // (0+6.67428e-11i)
fmt.Println(e4) // (0+12345i)
}
16進数浮動小数点の虚数
package main
import "fmt"
func main() {
// 16進数浮動小数点(0x1p-2 = 1 × 2^-2 = 0.25)
var hexFloat complex128 = 0x1p-2i
fmt.Println(hexFloat) // (0+0.25i)
// 他の例
var hf2 complex128 = 0x1p0i // 1 × 2^0 = 1i
var hf3 complex128 = 0x1p2i // 1 × 2^2 = 4i
var hf4 complex128 = 0x2p-1i // 2 × 2^-1 = 1i
fmt.Println(hf2, hf3, hf4)
}
5. 複素数の演算
基本的な四則演算
package main
import "fmt"
func main() {
c1 := 3 + 4i
c2 := 1 + 2i
// 加算
sum := c1 + c2
fmt.Println("加算:", sum) // (4+6i)
// 減算
diff := c1 - c2
fmt.Println("減算:", diff) // (2+2i)
// 乗算
prod := c1 * c2
// (3+4i)(1+2i) = 3 + 6i + 4i + 8i²
// = 3 + 10i - 8 (i² = -1)
// = -5 + 10i
fmt.Println("乗算:", prod) // (-5+10i)
// 除算
quot := c1 / c2
fmt.Println("除算:", quot) // (2.2-0.4i)
}
複素数の絶対値(大きさ)
package main
import (
"fmt"
"math/cmplx"
)
func main() {
c := 3 + 4i
// 絶対値(原点からの距離)
// |3+4i| = √(3² + 4²) = √25 = 5
abs := cmplx.Abs(c)
fmt.Println("絶対値:", abs) // 5
// 位相(角度)
phase := cmplx.Phase(c)
fmt.Printf("位相: %.4f ラジアン\n", phase)
}
共役複素数
package main
import (
"fmt"
"math/cmplx"
)
func main() {
c := 3 + 4i
// 共役複素数(虚数部の符号を反転)
conj := cmplx.Conj(c)
fmt.Println("共役:", conj) // (3-4i)
// 複素数とその共役の積は実数になる
prod := c * conj
fmt.Println("積:", prod) // (25+0i) = 25
}
6. 実用例
例1: 電気回路(インピーダンス)
package main
import (
"fmt"
"math/cmplx"
)
func main() {
// 交流回路のインピーダンス計算
// Z = R + jωL (抵抗 + 誘導リアクタンス)
R := 100.0 // 抵抗 (Ω)
L := 0.1 // インダクタンス (H)
omega := 314.0 // 角周波数 (rad/s) = 2π × 50Hz
Z := complex(R, omega*L) // インピーダンス
fmt.Printf("インピーダンス: %.2f\n", Z)
// 絶対値(インピーダンスの大きさ)
magZ := cmplx.Abs(Z)
fmt.Printf("インピーダンスの大きさ: %.2f Ω\n", magZ)
}
例2: 信号処理(フーリエ変換)
package main
import (
"fmt"
"math"
"math/cmplx"
)
func main() {
// 離散フーリエ変換(DFT)の基礎
// W_N^k = e^(-2πi k/N)
N := 8 // サンプル数
k := 2 // 周波数インデックス
// オイラーの公式: e^(iθ) = cos(θ) + i*sin(θ)
theta := -2 * math.Pi * float64(k) / float64(N)
w := complex(math.Cos(theta), math.Sin(theta))
fmt.Printf("W_%d^%d = %.4f\n", N, k, w)
// 絶対値は常に1
abs := cmplx.Abs(w)
fmt.Printf("絶対値: %.4f\n", abs)
}
例3: 2次方程式の解(虚数解)
package main
import (
"fmt"
"math"
"math/cmplx"
)
// 2次方程式 ax² + bx + c = 0 の解を求める
func solveQuadratic(a, b, c float64) (complex128, complex128) {
// 判別式
discriminant := b*b - 4*a*c
if discriminant >= 0 {
// 実数解
sqrt_d := math.Sqrt(discriminant)
x1 := complex((-b+sqrt_d)/(2*a), 0)
x2 := complex((-b-sqrt_d)/(2*a), 0)
return x1, x2
} else {
// 虚数解
sqrt_d := cmplx.Sqrt(complex(discriminant, 0))
x1 := (-complex(b, 0) + sqrt_d) / complex(2*a, 0)
x2 := (-complex(b, 0) - sqrt_d) / complex(2*a, 0)
return x1, x2
}
}
func main() {
// x² + 2x + 5 = 0
x1, x2 := solveQuadratic(1, 2, 5)
fmt.Printf("解1: %v\n", x1) // (-1+2i)
fmt.Printf("解2: %v\n", x2) // (-1-2i)
}
例4: マンデルブロ集合
package main
import (
"fmt"
"math/cmplx"
)
// マンデルブロ集合の判定
func mandelbrot(c complex128, maxIter int) int {
z := complex(0, 0)
for n := 0; n < maxIter; n++ {
z = z*z + c
if cmplx.Abs(z) > 2 {
return n // 発散
}
}
return maxIter // 収束(集合に含まれる)
}
func main() {
// いくつかの点でテスト
points := []complex128{
0 + 0i,
0.5 + 0i,
-1 + 0i,
0 + 1i,
-0.5 + 0.5i,
}
maxIter := 100
for _, c := range points {
iter := mandelbrot(c, maxIter)
if iter == maxIter {
fmt.Printf("%v: 集合に含まれる\n", c)
} else {
fmt.Printf("%v: %d回で発散\n", c, iter)
}
}
}
7. 複素数型の種類
Goには2種類の複素数型があります。
package main
import "fmt"
func main() {
// complex64: float32の実数部 + float32の虚数部
var c64 complex64 = 3 + 4i
fmt.Printf("complex64: %v (型: %T)\n", c64, c64)
// complex128: float64の実数部 + float64の虚数部(デフォルト)
var c128 complex128 = 3 + 4i
fmt.Printf("complex128: %v (型: %T)\n", c128, c128)
// 型推論はcomplex128になる
auto := 3 + 4i
fmt.Printf("型推論: %v (型: %T)\n", auto, auto)
}
まとめ: 虚数リテラルで覚えておくべきこと
虚数リテラルの作り方
- 整数 + i:
5i,42i,1_000i - 浮動小数点 + i:
3.14i,.5i,2.71828i - 指数表記 + i:
1e6i,6.67e-11i - 16進数 + i:
0xFFi,0x1p-2i - 8進数 + i:
0o123i
複素数の作り方
// 方法1: リテラルで直接
c1 := 3 + 4i
// 方法2: complex関数
c2 := complex(3, 4)
// 方法3: 実数部と虚数部を別々に
real := 3.0
imag := 4.0
c3 := complex(real, imag)
よく使う関数
import "math/cmplx"
c := 3 + 4i
real(c) // 実数部を取得: 3
imag(c) // 虚数部を取得: 4
cmplx.Abs(c) // 絶対値: 5
cmplx.Phase(c) // 位相(角度)
cmplx.Conj(c) // 共役複素数: 3-4i
cmplx.Sqrt(c) // 平方根
実用的なアドバイス
package main
import (
"fmt"
"math/cmplx"
)
func main() {
// 複素数は、信号処理、制御工学、量子力学などで使われる
// 基本的な使い方
z := 3 + 4i
// 演算
fmt.Println("加算:", z+1)
fmt.Println("乗算:", z*2)
fmt.Println("絶対値:", cmplx.Abs(z))
// 実部と虚部
fmt.Printf("実部: %.2f, 虚部: %.2f\n", real(z), imag(z))
}
虚数リテラルは、科学技術計算や信号処理で威力を発揮します。日常的なプログラミングではあまり使いませんが、特定の分野では必須の機能です!
おわりに
本日は、Go言語の言語仕様について解説しました。

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

コメント