
こんにちは。よっしーです(^^)
本日は、Go言語の言語仕様について解説しています。
背景
Go言語を学び始めて、公式の「The Go Programming Language Specification(言語仕様書)」を開いてみたものの、「英語で書かれていて読むのが大変…」「専門用語ばかりで何を言っているのかわからない…」と感じたことはありませんか? 実は、多くのGo初心者が同じ壁にぶつかっています。
言語仕様書は、Go言語の「正式な取扱説明書」のような存在です。プログラミング言語がどのように動くのか、どんなルールで書くべきなのかが詳しく書かれていますが、その分、初めて読む人には難しく感じられるのも事実です。
そこでこの記事では、言語仕様書の導入部分を丁寧な日本語訳とともに、初心者の方でも理解しやすい補足説明を加えてお届けします。「強く型付けされている」「ガベージコレクション」「並行プログラミング」といった専門用語も、具体例を交えながらわかりやすく解説していきます。
言語仕様書は難しそうに見えますが、一つひとつの概念を丁寧に読み解いていけば、必ず理解できます。一緒に、Go言語の基礎をしっかり学んでいきましょう!
clear(Clear)
組み込み関数 clear は、map、スライス、または型パラメータ型の引数を取り、すべての要素を削除またはゼロ化する [Go 1.21]。
呼び出し 引数の型 結果
clear(m) map[K]T すべてのエントリを削除し、
空のmapにする(len(m) == 0)
clear(s) []T s の長さまでのすべての要素を
T のゼロ値に設定する
clear(t) 型パラメータ 以下を参照
clear の引数の型が型パラメータの場合、その型集合のすべての型はmapまたはスライスでなければならず、clear は実際の型引数に対応する操作を実行する。
mapまたはスライスが nil の場合、clear は何もしない。
解説
clear ってなに?
clear は Go 1.21 で追加された組み込み関数で、スライスやmapの中身を一括でリセットする機能を提供します。
m := map[string]int{"a": 1, "b": 2, "c": 3}
clear(m)
fmt.Println(m) // map[]
fmt.Println(len(m)) // 0
map に対する clear:全エントリ削除
map に対して clear を使うと、すべてのキーと値が削除され、空のmapになります。
m := map[string]int{"x": 1, "y": 2, "z": 3}
clear(m)
fmt.Println(len(m)) // 0
fmt.Println(m) // map[]
clear の前は、ループで1つずつ delete するか、新しいmapを作り直す必要がありました。
// clear 以前の方法1:ループで削除
for k := range m {
delete(m, k)
}
// clear 以前の方法2:新しいmapに置き換え
m = make(map[string]int)
// Go 1.21 以降:一行で済む
clear(m)
clear と make で新規作成する方法の違いは、同じmapオブジェクトを再利用するかどうかです。clear は既存のmapをそのまま使い回すので、そのmapへの参照を持つ他の変数にも「空になった」ことが反映されます。
m1 := map[string]int{"a": 1}
m2 := m1 // m2 は m1 と同じmapを参照
clear(m1)
fmt.Println(m2) // map[](m2 にも反映される)
// make だと別のmapになる
m1 = make(map[string]int)
m1["b"] = 2
fmt.Println(m2) // map[](m2 は古いmapを指したまま)
スライスに対する clear:ゼロ値で埋める
スライスに対する clear の動作は、mapとは少し異なります。要素を削除するのではなく、すべての要素をゼロ値に設定します。長さや容量は変わりません。
s := []int{1, 2, 3, 4, 5}
clear(s)
fmt.Println(s) // [0 0 0 0 0]
fmt.Println(len(s)) // 5(長さは変わらない)
fmt.Println(cap(s)) // 5(容量も変わらない)
ポインタや参照型の要素を含むスライスでは、clear がゼロ値(nil)を設定することでガベージコレクションの対象になるので、メモリリークの防止にも役立ちます。
type Data struct {
buf []byte
}
s := []*Data{{buf: make([]byte, 1000)}, {buf: make([]byte, 1000)}}
s = s[:0] // 長さを0にしても、基底配列の要素はまだポインタを保持している
// clear を使えばポインタが nil になり、Data がGC対象になる
nil に対しては何もしない
nil のmapやスライスに対して clear を呼んでも、パニックしません。単に何もしません。
var m map[string]int // nil
clear(m) // 何も起きない(パニックしない)
var s []int // nil
clear(s) // 何も起きない
安全に呼び出せるので、nil チェックを事前に入れる必要はありません。
map と スライスでの動作の違いに注意
この違いは混同しやすいので整理しておきましょう。
| 対象 | 動作 | 長さの変化 |
|---|---|---|
| map | 全エントリを削除 | len が 0 になる |
| スライス | 全要素をゼロ値に設定 | len は変わらない |
mapは「中身を空にする」、スライスは「中身をリセットする」と覚えるとわかりやすいです。スライスの長さも0にしたい場合は、別途 s = s[:0] と書く必要があります。
おわりに
本日は、Go言語の言語仕様について解説しました。

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

コメント