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

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

このコミットは、Go言語のGo 1リリースにおけるマップからの要素削除の構文変更に関するドキュメント更新です。具体的には、doc/go1.html および doc/go1.tmpl ファイルに、マップからの要素削除の新しい組み込み関数 delete の導入と、古い構文からの移行方法に関する説明が追加されています。また、この変更を説明するための新しいGoプログラムの例 (doc/progs/go1.go) も追加されています。

コミット

commit 2fa987b6cd135fb9a337a55b02cf073956fcae56
Author: Rob Pike <r@golang.org>
Date:   Wed Dec 7 16:11:17 2011 -0800

    doc/go1: map deletion
    This CL is in part a proposal for how to write these sections:
    - Brief discussion of change
    - No attempt to analyze the thinking about it
    - Old code
    - New code, runnable if possible
    - How to update old programs

    R=golang-dev, remyoudompheng, gri, adg
    CC=golang-dev
    https://golang.org/cl/5454044

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

https://github.com/golang/go/commit/2fa987b6cd135fb9a337a55b02cf073956fcae56

元コミット内容

このコミットは、Go 1リリースノートのドキュメント (doc/go1.html および doc/go1.tmpl) に、マップからの要素削除に関するセクションを追加するものです。コミットメッセージには、これらのセクションの記述方法に関する提案も含まれています。

  • 変更点の簡単な説明
  • 変更に至るまでの思考の分析は行わない
  • 古いコードの例
  • 新しいコードの例(可能であれば実行可能なもの)
  • 古いプログラムを更新する方法

変更の背景

Go言語は、2012年3月28日に最初の安定版リリースであるGo 1をリリースしました。Go 1の目標は、言語と標準ライブラリの安定した基盤を提供し、長期的なコミットメントを可能にすることでした。この安定化の一環として、既存の言語機能の一部が見直され、より一貫性があり、使いやすいAPIが提供されることになりました。

マップからの要素削除の構文もその一つでした。Go 1以前のGo言語では、マップから要素を削除するために m[x] = ignored, false という特殊な多値代入構文を使用していました。この構文は直感的ではなく、いくつかの問題点がありました。例えば、ignored という変数が実際に使用されない場合でも宣言する必要があるなど、冗長性や混乱を招く可能性がありました。

このコミットは、Go 1のリリースに向けて、このマップ削除の構文をより明確でGoらしい方法に変更するためのドキュメント更新です。新しい組み込み関数 delete の導入により、マップからの要素削除がよりシンプルかつ意図が明確な操作として表現できるようになりました。

前提知識の解説

Go言語のマップ (Map)

Go言語のマップは、キーと値のペアを格納するハッシュテーブルの実装です。他の言語の辞書や連想配列に相当します。マップは make 関数で作成され、map[KeyType]ValueType の形式で宣言されます。

例:

m := make(map[string]int) // キーがstring、値がintのマップ

マップへの値の追加や更新は m[key] = value で行い、値の取得は value := m[key] で行います。マップから存在しないキーを読み取ると、値の型のゼロ値が返されます。キーの存在を確認するには、多値代入を使用します。

例:

value, ok := m[key]
if ok {
    // キーが存在する
} else {
    // キーが存在しない
}

Go 1の互換性保証

Go 1は、Go言語の歴史において非常に重要なマイルストーンです。Go 1のリリース以降、Goチームは「Go 1互換性保証」を導入しました。これは、Go 1仕様に準拠して書かれたプログラムは、将来のGoのバージョンでもコンパイルされ、実行され続けることを保証するものです。この保証は、Go言語が企業や大規模プロジェクトで安心して採用されるための重要な要素となりました。

gofixツール

gofix は、Go言語のコードを新しいAPIや構文に自動的に更新するためのコマンドラインツールです。Go 1のリリースに伴い、以前のバージョンで書かれたコードをGo 1の仕様に準拠させるために gofix が広く利用されました。gofix は、特定のパターンに一致するコードを検出し、自動的に修正を適用することができます。これにより、開発者は手動で大量のコードを修正する手間を省くことができました。

技術的詳細

このコミットの主要な技術的変更は、Go言語におけるマップからの要素削除の構文が、特殊な多値代入から専用の組み込み関数 delete へと変更されたことです。

古いマップ削除構文

Go 1以前では、マップ m からキー x に対応する要素を削除するには、以下の構文を使用していました。

m[x] = ignored, false

この構文は、マップの要素に値を代入する際に、2つの値を返すというGoの多値代入の特性を逆手に取ったものでした。ignored は通常、_ (ブランク識別子) を使用して破棄される値であり、false はキーが存在しないことを示すために使用されました。この方法は、マップから要素を削除するという意図を直接的に表現しているとは言えず、Go言語の設計思想である「明示的であること」に反していました。

新しいマップ削除構文 (delete 関数)

Go 1からは、マップからの要素削除のために新しい組み込み関数 delete が導入されました。

delete(m, k)

ここで、m はマップ、k は削除したい要素のキーです。

delete 関数の特徴:

  • 戻り値がない: delete 関数は、要素が削除されたかどうかを示す戻り値を持ちません。これは、Go言語の設計哲学として、エラーが発生しない操作には戻り値を持たせないという原則に基づいています。
  • 存在しないキーの削除: 存在しないキーを delete 関数に渡しても、ランタイムエラーは発生せず、何もしません(no-op)。これは、マップ操作の堅牢性を高めます。
  • 意図の明確化: delete という関数名が、その操作の意図を明確に示しており、コードの可読性が向上します。

gofix による移行

この構ートのドキュメントにも記載されている通り、gofix ツールは、古い m[k] = ignored, false 構文を新しい delete(m, k) 構文に自動的に変換する機能を提供しました。

gofix は、ignored の値が安全に破棄できる場合(例えば、_ が使用されている場合)や、false が事前定義されたブール定数を参照している場合に、自動変換を行います。それ以外の、より複雑なケースでは、gofix はプログラマによる手動での確認と修正が必要であることを示すフラグを立てました。これにより、Go 1への移行がスムーズに行われるよう支援されました。

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

このコミットは主にドキュメントの変更であり、Go言語のコンパイラやランタイムのコード自体を変更するものではありません。変更は doc/go1.htmldoc/go1.tmpl に集中しており、新しいマップ削除構文に関する説明が追加されています。また、この説明を補完するための実行可能なコード例が doc/progs/go1.go として新規追加されています。

  • doc/go1.html: Go 1リリースノートのHTML版。マップ削除に関する新しいセクションが追加されています。
  • doc/go1.tmpl: doc/go1.html のテンプレートファイル。同様にマップ削除に関するセクションが追加されています。
  • doc/progs/go1.go: 新しい delete 関数を使用したマップ削除の例を含むGoプログラム。
  • doc/progs/run: doc/progs/go1.go を実行するためのスクリプトに、新しいプログラムの実行が追加されています。

具体的な変更内容としては、doc/go1.htmldoc/go1.tmpl<h3 id="delete">Deleting from maps</h3> の部分が <h3 id="map_deletion">Deleting from maps</h3> に変更され、その下にマップ削除に関する詳細な説明が追加されています。

追加されたHTML/テンプレートの抜粋:

<h3 id="map_deletion">Deleting from maps</h3>

<p>
The original syntax for deleting an element in a map was:
</p>

<pre>
    m[x] = ignored, false
</pre>

<p>
This syntax had a number of minor problems and is being replaced.
As of Go 1, that syntax is gone and in its place is a new built-in
function, <code>delete</code>.  The call
</p>

<pre><!--{{code "progs/go1.go" `/delete\\(m, k\\)/`}}
-->    delete(m, k)
</pre>

<p>
will delete the map entry retrieved by the expression <code>m[k]</code>.
There is no return value. Deleting a non-existent entry is a no-op.
</p>

<p>
<em>Updating</em>:
Gofix will convert expressions of the form <code>m[k] = ignored,
false</code> into <code>delete(m, k)</code> when it is clear that
the ignored value can be safely discarded from the program and
<code>false</code> refers to the predefined boolean constant.  Gofix
will flag other uses of the syntax for inspection by the programmer.
</p>

新しく追加された doc/progs/go1.go の内容:

// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file contains examples to embed in the Go 1 release notes document.

package main

import "log"

func main() {
	mapDelete()
}

func mapDelete() {
	m := map[string]int{"7": 7, "23": 23}
	k := "7"
	delete(m, k)
	if m["7"] != 0 || m["23"] != 23 {
		log.Fatal("mapDelete:", m)
	}
}

この go1.go ファイルは、delete 関数が正しく動作することを確認するための簡単なテストケースを含んでいます。

コアとなるコードの解説

このコミットの「コアとなるコード」は、Go 1リリースノートのドキュメントに追加された、マップからの要素削除に関する説明と、その説明を補完するGoのコード例です。

ドキュメントの追加

doc/go1.htmldoc/go1.tmpl に追加されたセクションは、Go 1におけるマップ削除の変更点を明確に説明しています。

  • 古い構文の提示: m[x] = ignored, false という古い構文を提示し、その問題点に軽く触れています。
  • 新しい delete 関数の紹介: delete(m, k) という新しい組み込み関数を導入し、その使い方と特性(戻り値がないこと、存在しないキーの削除がno-opであること)を説明しています。
  • gofix による移行支援: gofix ツールが古い構文から新しい構文への自動変換をどのように行うか、また、どのような場合に手動での確認が必要になるかを説明しています。これは、既存のGoプログラムをGo 1に移行する開発者にとって非常に重要な情報でした。

コード例 (doc/progs/go1.go)

doc/progs/go1.go は、delete 関数の基本的な使用方法を示す簡潔な例です。

  • mapDelete() 関数内で、map[string]int 型のマップ m を初期化しています。
  • delete(m, k) を呼び出すことで、キー k ("7") に対応する要素をマップから削除しています。
  • 削除後のマップの状態を検証するために、if m["7"] != 0 || m["23"] != 23 という条件でアサーションを行っています。Goのマップから存在しないキーを読み取るとゼロ値が返されるため、m["7"]0 であることを確認しています。また、削除されていないキー m["23"] が元の値 23 を保持していることも確認しています。
  • この例は、delete 関数が意図通りに動作し、指定されたキーの要素をマップから削除することを示しています。

これらのドキュメントとコード例は、Go 1の重要な変更点の一つであるマップ削除の構文変更を、開発者が理解し、自身のコードに適用するための明確なガイドラインを提供しています。

関連リンク

参考にした情報源リンク