Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 10006] ファイルの概要

Go言語仕様において、map要素の削除を行うためのdelete組み込み関数の追加と、従来の特殊な代入形式による削除方法の廃止を行った重要なコミットです。

コミット

  • コミットハッシュ: 3e0c0a8add600cd395c4e30a4db8cc1ede90acc9
  • 作成者: Robert Griesemer gri@golang.org
  • 日付: 2011年10月17日 12:53:10 -0700
  • コミットメッセージ: "go spec: "delete" built-in function"
  • レビュー: R=golang-dev, r, rsc

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/3e0c0a8add600cd395c4e30a4db8cc1ede90acc9

元コミット内容

commit 3e0c0a8add600cd395c4e30a4db8cc1ede90acc9
Author: Robert Griesemer <gri@golang.org>
Date:   Mon Oct 17 12:53:10 2011 -0700

    go spec: "delete" built-in function
    
    R=golang-dev, r, rsc
    CC=golang-dev
    https://golang.org/cl/5272045
---
 doc/go_spec.html | 43 +++++++++++++++++++++++++------------------
 1 file changed, 25 insertions(+), 18 deletions(-)

diff --git a/doc/go_spec.html b/doc/go_spec.html
index 810df2c46a..4c1ecef353 100644
--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -1159,9 +1159,10 @@ map [string] interface {}
 The number of map elements is called its length.
 For a map <code>m</code>, it can be discovered using the
 built-in function <a href="#Length_and_capacity"><code>len(m)</code></a>
-and may change during execution. Elements may be added and removed
-during execution using special forms of <a href="#Assignments">assignment</a>;
-and they may be accessed with <a href="#Indexes">index</a> expressions.
+and may change during execution. Elements may be added during execution
+using <a href="#Assignments">assignments</a> and retrieved with
+<a href="#Indexes">index</a> expressions; they may be removed with the
+<a href="#Deletion_of_map_elements"><code>delete</code></a> built-in function.
 </p>
 <p>
 A new, empty map value is made using the built-in
@@ -2431,21 +2432,6 @@ where the result of the index expression is a pair of values with types
 <code>a[x]</code> as in the single-result form.
 </p>
 
-<p>
-Similarly, if an assignment to a map element has the special form
-</p>
-
-<pre>
-a[x] = v, ok
-</pre>
-
-<p>
-and boolean <code>ok</code> has the value <code>false</code>,
-the entry for key <code>x</code> is deleted from the map; if
-<code>ok</code> is <code>true</code>, the construct acts like
-a regular assignment to an element of the map.
-</p>
-
 <p>
 Assigning to an element of a <code>nil</code> map causes a
 <a href="#Run_time_panics">run-time panic</a>.
@@ -4738,6 +4724,27 @@ n2 := copy(s, s[2:])            // n2 == 4, s == []int{2, 3, 4, 5, 4, 5}
 n3 := copy(b, "Hello, World!")  // n3 == 5, b == []byte("Hello")
 </pre>
 
+
+<h3 id="Deletion_of_map_elements">Deletion of map elements</h3>
+
+<p>
+The built-in function <code>delete</code> removes the element with key
+<code>k</code> from a <a href="#Map_types">map</a> <code>m</code>. The
+type of <code>k</code> must be <a href="#Assignability">assignable</a>
+to the key type of <code>m</code>.
+</p>
+
+<pre class="grammar">
+delete(m, k)  // remove element m[k] from map m
+</pre>
+
+<p>
+If the element <code>m[k]</code> does not exist, <code>delete</code> is
+a no-op. Calling <code>delete</code> with a nil map causes a
+<a href="#Run_time_panics">run-time panic</a>.
+</p>
+
+
 <h3 id="Complex_numbers">Assembling and disassembling complex numbers</h3>
 
 <p>

このコミットは、Go言語仕様書(doc/go_spec.html)に対して43行の変更を加えました(25行追加、18行削除)。

主な変更点:

  1. map要素の削除についての新しい仕様の追加
  2. 従来の特殊な代入形式による削除方法の記述を削除
  3. 新しいdelete組み込み関数の仕様と使用方法の追加

変更の背景

Go言語のGo 1.0リリースに向けて、map要素の削除方法が根本的に見直されました。従来のGo言語では、mapから要素を削除するために以下のような特殊な代入構文を使用していました:

a[x] = v, ok

この構文では、okfalseの場合にキーxに対応する要素が削除されるという仕組みでした。しかし、この構文は直感的でなく、多くの開発者にとって理解しづらいものでした。

2011年は、Go言語が2009年に発表されてから2年が経過し、Go 1.0リリース(2012年3月)に向けて言語仕様の安定化が進められていた時期でした。この時期に、より直感的で理解しやすいdelete組み込み関数の導入が決定されました。

従来の問題点

Go 1.0以前では、mapから要素を削除するために以下のような特殊な代入構文が使用されていました:

a[x] = v, ok

この構文では、okfalseの場合にキーxに対応する要素が削除される仕組みでした。しかし、この構文は以下のような問題を抱えていました:

  1. 直感的でない: 削除という操作が代入文の形で表現されていた
  2. 特殊すぎる: 言語仕様における唯一の2対1代入の例であった
  3. 無駄な要素: vは通常無視されるが、評価されて破棄される
  4. 固定値: okは事実上常に定数falseである必要があった
  5. 一貫性の欠如: 他の操作と比べて異質な構文であった

設計判断の理由

このコミットが行われた2011年10月の時点で、Go言語チームは以下の理由からdelete組み込み関数の仕様を明確化する必要がありました:

  1. Go 1.0への準備: 2012年3月のGo 1.0リリースに向けた仕様の安定化
  2. map操作の統一: 他の組み込み関数と一貫した設計思想の実現
  3. コミュニティからの要望: 開発者コミュニティからの分かりやすい構文への要求
  4. 保守性の向上: 特殊な構文よりも明示的な関数による操作の推奨

Robert Griesemer、Rob Pike、Ken Thompsonといった言語設計者たちは、この奇妙な構文を廃止し、より明確で一貫性のあるdelete組み込み関数を正式化することを決定しました。

前提知識の解説

Go言語のmap型について

Go言語のmap型は、キーと値のペアを格納する組み込みの参照型です。以下のような特徴があります:

  1. 動的なサイズ: 実行時に要素の追加・削除が可能
  2. ハッシュテーブル実装: 高速な検索・挿入・削除が可能
  3. nil値の扱い: nil mapへの代入はランタイムパニックを発生
  4. 型安全性: キーと値の型が静的に決定される

組み込み関数について

Go言語の組み込み関数は、特別なインポート文なしに使用できる関数群です:

  • len(): 長さを取得
  • cap(): 容量を取得
  • make(): スライス、map、チャンネルの作成
  • new(): 型のゼロ値へのポインタを作成
  • copy(): スライスのコピー
  • delete(): map要素の削除(このコミットで追加)

Robert Griesemer について

Robert Griesemer(1964年生まれ)は、スイス出身のコンピュータ科学者で、Go言語の共同設計者の一人です。彼は以下の重要なプロジェクトに携わっています:

  • Go言語の設計と実装(Rob Pike、Ken Thompsonと共同)
  • Google V8 JavaScriptエンジンの開発
  • Java HotSpot仮想マシンの開発
  • Strongtalkシステムの開発

技術的詳細

仕様変更の詳細

このコミットでは、以下の技術的変更が行われました:

  1. map要素の削除方法の統一

    • 従来のa[x] = v, ok構文を廃止
    • 新しいdelete(m, k)関数の導入
  2. エラーハンドリングの改善

    • 存在しないキーの削除は無操作(no-op)
    • nil mapに対するdelete呼び出しもランタイムパニック回避
  3. 型安全性の向上

    • キーの型はmapのキー型に代入可能である必要がある
    • コンパイル時の型チェックが強化

パフォーマンスへの影響

delete関数の導入により、以下のパフォーマンス改善が期待されます:

  1. コンパイル時最適化: 専用の組み込み関数により、コンパイラが最適化を行いやすくなる
  2. ランタイム効率: 特殊な代入構文よりも直接的なハッシュテーブル操作が可能
  3. メモリ効率: 不要な値の割り当てが削減される

コアとなるコードの変更箇所

削除された仕様(従来の方法)

<p>
Similarly, if an assignment to a map element has the special form
</p>

<pre>
a[x] = v, ok
</pre>

<p>
and boolean <code>ok</code> has the value <code>false</code>,
the entry for key <code>x</code> is deleted from the map; if
<code>ok</code> is <code>true</code>, the construct acts like
a regular assignment to an element of the map.
</p>

追加された仕様(新しい方法)

<h3 id="Deletion_of_map_elements">Deletion of map elements</h3>

<p>
The built-in function <code>delete</code> removes the element with key
<code>k</code> from a <a href="#Map_types">map</a> <code>m</code>. The
type of <code>k</code> must be <a href="#Assignability">assignable</a>
to the key type of <code>m</code>.
</p>

<pre class="grammar">
delete(m, k)  // remove element m[k] from map m
</pre>

<p>
If the element <code>m[k]</code> does not exist, <code>delete</code> is
a no-op. Calling <code>delete</code> with a nil map causes a
<a href="#Run_time_panics">run-time panic</a>.
</p>

map型の説明部分の更新

<!-- 変更前 -->
Elements may be added and removed
during execution using special forms of <a href="#Assignments">assignment</a>;
and they may be accessed with <a href="#Indexes">index</a> expressions.

<!-- 変更後 -->
Elements may be added during execution
using <a href="#Assignments">assignments</a> and retrieved with
<a href="#Indexes">index</a> expressions; they may be removed with the
<a href="#Deletion_of_map_elements"><code>delete</code></a> built-in function.

コアとなるコードの解説

1. 新しいdelete関数の構文

delete(m, k)
  • m: 削除対象のmap
  • k: 削除するキー
  • 戻り値なし(void関数)

2. 型制約

// キーの型はmapのキー型に代入可能である必要がある
var m map[string]int
var k string = "key"
delete(m, k)  // OK

var invalidKey int = 123
delete(m, invalidKey)  // コンパイルエラー

3. エラーハンドリング

// 存在しないキーの削除は無操作
m := make(map[string]int)
delete(m, "nonexistent")  // エラーなし、何も起こらない

// nil mapへの削除はパニック
var nilMap map[string]int
delete(nilMap, "key")  // ランタイムパニック

4. 実用的な使用例

// ユーザーセッションの管理
sessions := make(map[string]*Session)

// セッションの追加
sessions["user123"] = &Session{...}

// セッションの削除
delete(sessions, "user123")

// 条件付き削除
if session, exists := sessions["user123"]; exists {
    session.Cleanup()
    delete(sessions, "user123")
}

5. 従来の方法との比較

// 従来の方法(廃止)
m[key] = value, false  // keyを削除

// 新しい方法
delete(m, key)  // keyを削除

新しい方法の利点:

  • 直感的で理解しやすい
  • 不要な値の割り当てが不要
  • コンパイラによる最適化が容易
  • 他の言語の慣習に近い

関連リンク

参考にした情報源リンク