
こんにちは。よっしーです(^^)
本日は、Go言語の言語仕様について解説しています。
背景
Go言語を学び始めて、公式の「The Go Programming Language Specification(言語仕様書)」を開いてみたものの、「英語で書かれていて読むのが大変…」「専門用語ばかりで何を言っているのかわからない…」と感じたことはありませんか? 実は、多くのGo初心者が同じ壁にぶつかっています。
言語仕様書は、Go言語の「正式な取扱説明書」のような存在です。プログラミング言語がどのように動くのか、どんなルールで書くべきなのかが詳しく書かれていますが、その分、初めて読む人には難しく感じられるのも事実です。
そこでこの記事では、言語仕様書の導入部分を丁寧な日本語訳とともに、初心者の方でも理解しやすい補足説明を加えてお届けします。「強く型付けされている」「ガベージコレクション」「並行プログラミング」といった専門用語も、具体例を交えながらわかりやすく解説していきます。
言語仕様書は難しそうに見えますが、一つひとつの概念を丁寧に読み解いていけば、必ず理解できます。一緒に、Go言語の基礎をしっかり学んでいきましょう!
min と max(Min and max)
組み込み関数 min と max は、順序付き型の固定数の引数のうち、それぞれ最小値または最大値を計算する。少なくとも1つの引数が必要である [Go 1.21]。
演算子と同じ型のルールが適用される。順序付きの引数 x と y に対して、x + y が有効であれば min(x, y) は有効であり、min(x, y) の型は x + y の型と同じである(max についても同様)。すべての引数が定数の場合、結果は定数である。
var x, y int
m := min(x) // m == x
m := min(x, y) // m は x と y の小さいほう
m := max(x, y, 10) // m は x と y の大きいほう、ただし少なくとも 10
c := max(1, 2.0, 10) // c == 10.0(浮動小数点の種別)
f := max(0, float32(x)) // f の型は float32
var s []string
_ = min(s...) // 不正: スライス引数は許可されない
t := max("", "foo", "bar") // t == "foo"(文字列の種別)
数値引数に対して、すべての NaN が等しいと仮定すると、min と max は可換かつ結合的である:
min(x, y) == min(y, x)
min(x, y, z) == min(min(x, y), z) == min(x, min(y, z))
浮動小数点引数の負のゼロ、NaN、および無限大には以下のルールが適用される:
x y min(x, y) max(x, y)
-0.0 0.0 -0.0 0.0 // 負のゼロは(非負の)ゼロより小さい
-Inf y -Inf y // 負の無限大は他のどの数より小さい
+Inf y y +Inf // 正の無限大は他のどの数より大きい
NaN y NaN NaN // いずれかの引数が NaN の場合、結果は NaN
文字列引数に対して、min の結果はバイト単位で辞書順に比較して最小(または max の場合は最大)の値を持つ最初の引数である:
min(x, y) == if x <= y then x else y
min(x, y, z) == min(min(x, y), z)
解説
min と max の基本
Go 1.21 で追加された、引数の中から最小値・最大値を返す組み込み関数です。
min(3, 1, 4, 1, 5) // 1
max(3, 1, 4, 1, 5) // 5
それまでは自分で比較を書くか、math.Min/math.Max(float64 専用)を使う必要がありましたが、min/max はどの順序付き型でも使えます。
// Go 1.21 以前
if a < b {
result = a
} else {
result = b
}
// Go 1.21 以降
result := min(a, b)
引数は2つ以上でもOK
m := min(5, 3, 8, 1, 9) // 1
m := max(5, 3, 8, 1, 9) // 9
引数が1つでも使えます(そのまま返されます)。
m := min(42) // 42
ただし、スライスを ... で展開して渡すことはできません。
s := []int{5, 3, 8}
min(s...) // コンパイルエラー!
スライスの最小値が欲しい場合は slices.Min を使います。
import "slices"
m := slices.Min([]int{5, 3, 8}) // 3
型のルール
min/max の型ルールは演算子と同じです。「x + y が有効なら min(x, y) も有効」と覚えましょう。
var x int
var y int
min(x, y) // ✅ int + int が有効 → min も有効
var f float32
min(0, f) // ✅ 0 は型なし定数なので float32 に変換される。結果は float32
min(1, 2.0, 10) // ✅ 型なし定数同士。最も広い種別(浮動小数点)になる → 10.0
異なる型なし定数を混ぜた場合は、以前学んだ「種別の昇格ルール」(整数 → ルーン → 浮動小数点 → 複素数)が適用されます。
文字列にも使える
min/max は順序付き型すべてに使えるので、文字列にも使えます。
t := max("", "foo", "bar") // "foo"
m := min("apple", "banana") // "apple"
比較はバイト単位の辞書順です。
よくある使い方
1. 値を範囲内に収める(クランプ)
func clamp(v, lo, hi int) int {
return max(lo, min(v, hi))
}
clamp(15, 0, 10) // 10(上限に制限される)
clamp(-5, 0, 10) // 0(下限に制限される)
clamp(5, 0, 10) // 5(範囲内なのでそのまま)
2. デフォルト値の保証
m := max(x, y, 10) // x と y の大きいほう、ただし最低でも 10
原文の例にあるこのパターンは「最低保証」として実用的です。
3. バッファサイズの決定
bufSize := max(len(data), 1024) // データサイズか 1024 の大きいほう
浮動小数点の特殊な値
NaN と負のゼロの扱いは知っておくと安心です。
NaN は「伝染する」
min(1.0, math.NaN()) // NaN
max(1.0, math.NaN()) // NaN
引数のどれか1つでも NaN があると、結果は NaN になります。
負のゼロは正のゼロより小さい
min(-0.0, 0.0) // -0.0
max(-0.0, 0.0) // 0.0
通常のプログラミングで気にすることはほとんどありませんが、IEEE 754 の厳密な動作が求められる場面では重要です。
定数式として使える
すべての引数が定数なら、結果も定数です。
const maxSize = max(defaultSize, minRequired, userConfig)
コンパイル時に計算されるので、実行時のコストはありません。
おわりに
本日は、Go言語の言語仕様について解説しました。

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

コメント