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

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

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

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

スポンサーリンク

背景

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

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

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

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

min と max(Min and max)

組み込み関数 minmax は、順序付き型の固定数の引数のうち、それぞれ最小値または最大値を計算する。少なくとも1つの引数が必要である [Go 1.21]。

演算子と同じ型のルールが適用される。順序付きの引数 xy に対して、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 が等しいと仮定すると、minmax は可換かつ結合的である:

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.Maxfloat64 専用)を使う必要がありましたが、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言語の言語仕様について解説しました。

よっしー
よっしー

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

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

コメント

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