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

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

このコミットは、Go言語の標準ライブラリである net/http パッケージのテストコードにおけるビルドエラーを修正するものです。具体的には、HTTPリクエストおよびレスポンスのテスト構造体における url.Values および http.Header フィールドの初期化に関する修正が含まれています。

コミット

commit 8998673cc60a53013f6461fecf90b25abd003982
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date:   Tue Nov 15 14:04:58 2011 +0900

    net/http: fix build

    empty is already not a nil.

    R=golang-dev, bradfitz, rsc
    CC=golang-dev
    https://golang.org/cl/5376099

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

https://github.com/golang/go/commit/8998673cc60a53013f6461fecf90b25abd003982

元コミット内容

diff --git a/src/pkg/net/http/readrequest_test.go b/src/pkg/net/http/readrequest_test.go
index 2219d43316..c64fff6109 100644
--- a/src/pkg/net/http/readrequest_test.go
+++ b/src/pkg/net/http/readrequest_test.go
@@ -70,7 +70,6 @@ var reqTests = []reqTest{\n 			Close:         false,\n 			ContentLength: 7,\n 			Host:          "www.techcrunch.com",\n-\t\t\tForm:          url.Values{},\n \t\t},\n
 \t\t"abcdef\n",\n@@ -94,10 +93,10 @@ var reqTests = []reqTest{\n 			Proto:         "HTTP/1.1",\n 			ProtoMajor:    1,\n 			ProtoMinor:    1,\n+\t\t\tHeader:        Header{},\n \t\t\tClose:         false,\n 			ContentLength: 0,\n 			Host:          "foo.com",\n-\t\t\tForm:          url.Values{},\n \t\t},\n
 \t\tnoBody,\n@@ -131,7 +130,6 @@ var reqTests = []reqTest{\n 			Close:         false,\n 			ContentLength: 0,\n 			Host:          "test",\n-\t\t\tForm:          url.Values{},\n \t\t},\n
 \t\tnoBody,\n@@ -180,9 +178,9 @@ var reqTests = []reqTest{\n 			Proto:            "HTTP/1.1",\n 			ProtoMajor:       1,\n 			ProtoMinor:       1,\n+\t\t\tHeader:           Header{},\n 			ContentLength:    -1,\n 			Host:             "foo.com",\n-\t\t\tForm:             url.Values{},\n \t\t},\n
 \t\t"foobar",\ndiff --git a/src/pkg/net/http/response_test.go b/src/pkg/net/http/response_test.go
index 79dd8b8271..e5d01698e5 100644
--- a/src/pkg/net/http/response_test.go
+++ b/src/pkg/net/http/response_test.go
@@ -65,6 +65,7 @@ var respTests = []respTest{\n 			Proto:         "HTTP/1.1",\n 			ProtoMajor:    1,\n 			ProtoMinor:    1,\n+\t\t\tHeader:        Header{},\n 			Request:       dummyReq("GET"),\n 			Close:         true,\n 			ContentLength: -1,\n@@ -85,6 +86,7 @@ var respTests = []respTest{\n 			Proto:         "HTTP/1.1",\n 			ProtoMajor:    1,\n 			ProtoMinor:    1,\n+\t\t\tHeader:        Header{},\n 			Request:       dummyReq("GET"),\n 			Close:         false,\n 			ContentLength: 0,\n```

## 変更の背景

このコミットの主な目的は、`net/http` パッケージのビルドエラーを修正することです。コミットメッセージにある「empty is already not a nil.」という記述が、この変更の核心を突いています。

Go言語では、マップ型のゼロ値は `nil` です。`nil` のマップは要素を追加することができません。しかし、`make(map[key]value)` や `map[key]value{}` のように初期化されたマップは、たとえ要素が空であっても `nil` ではありません。

このコミットが行われた時点のGoのバージョンでは、`http.Request` 構造体の `Form` フィールド(型は `url.Values`、実体は `map[string][]string`)や `http.Header` 構造体の `Header` フィールド(型は `http.Header`、実体は `map[string][]string`)の扱いに関して、テストコードと実際の動作に不整合があった可能性があります。

具体的には、`readrequest_test.go` では `Form: url.Values{},` という記述が複数箇所で削除されています。これは、`url.Values{}` と明示的に初期化しなくても、`Form` フィールドがデフォルトで `nil` ではない空のマップとして扱われるようになったか、あるいはテストの文脈において `nil` であっても問題ない、または `nil` であることを期待するようになったためと考えられます。もし `Form` フィールドが `nil` のままで、その後に要素を追加しようとするとパニックが発生するため、この変更は `url.Values` のゼロ値の挙動が変更されたか、またはテストがその挙動に依存しないように修正されたことを示唆しています。

一方で、`readrequest_test.go` と `response_test.go` の両方で `Header: Header{},` という記述が追加されています。これは、`Header` フィールドが `nil` のままだと問題が発生するため、明示的に空のマップとして初期化する必要があったことを示しています。例えば、`Header` フィールドが `nil` の場合に、そのマップに対して操作(例: `Header.Add()`)を行おうとするとランタイムパニックが発生します。この修正は、テストが `Header` フィールドが常に非`nil`のマップであることを期待しているか、または `net/http` パッケージの内部で `Header` フィールドが非`nil`であることを前提とした処理が追加されたことを示唆しています。

要するに、このコミットは、Goのマップのゼロ値の挙動と、`net/http` パッケージ内の `url.Values` および `http.Header` の利用方法との間の整合性を取ることで、ビルドエラーを解消したものです。

## 前提知識の解説

### Go言語におけるマップのゼロ値と初期化

Go言語において、マップ(`map[KeyType]ValueType`)のゼロ値は `nil` です。`nil` のマップは、キーと値のペアを保持するためのメモリが割り当てられていない状態を指します。`nil` のマップに対して要素を追加しようとすると、ランタイムパニック(`panic: assignment to entry in nil map`)が発生します。

マップを初期化する方法はいくつかあります。

1.  **`make` 関数を使用する**:
    ```go
    m := make(map[string]int) // 空の非nilマップを作成
    ```
2.  **マップリテラルを使用する**:
    ```go
    m := map[string]int{} // 空の非nilマップを作成
    m := map[string]int{"key": 1} // 初期値を持つ非nilマップを作成
    ```

`map[string]int{}` のようにマップリテラルで初期化すると、たとえ要素が空であっても、それは `nil` ではない空のマップになります。このマップには後から要素を追加することができます。

### `net/http` パッケージ

`net/http` パッケージは、Go言語でHTTPクライアントとサーバーを実装するための機能を提供します。このパッケージは、HTTPリクエスト、レスポンス、ヘッダー、URLなどの構造体を定義しています。

*   **`http.Request` 構造体**: クライアントからのHTTPリクエストを表します。この構造体には、リクエストメソッド、URL、ヘッダー、ボディなどの情報が含まれます。
    *   `Form` フィールド: `url.Values` 型で、POSTリクエストのフォームデータやURLのクエリパラメータを保持します。
*   **`http.Response` 構造体**: サーバーからのHTTPレスポンスを表します。この構造体には、ステータスコード、ヘッダー、ボディなどの情報が含まれます。
    *   `Header` フィールド: `http.Header` 型で、HTTPレスポンスヘッダーを保持します。

### `url.Values` 型

`url.Values` は `map[string][]string` のエイリアス型です。これは、URLのクエリパラメータ(例: `?key1=value1&key2=value2`)や、`application/x-www-form-urlencoded` 形式のフォームデータを表現するために使用されます。一つのキーに対して複数の値を持つことができるため、`[]string` のスライスが値として使われます。

### `http.Header` 型

`http.Header` も `map[string][]string` のエイリアス型です。これは、HTTPリクエストまたはレスポンスのヘッダーを表現するために使用されます。HTTPヘッダーも一つのヘッダー名に対して複数の値を持つことができるため、`[]string` のスライスが値として使われます。

## 技術的詳細

このコミットの技術的詳細は、Go言語におけるマップのゼロ値の挙動と、`net/http` パッケージのテストコードにおける構造体の初期化のベストプラクティスに関連しています。

### `Form: url.Values{},` の削除

`http.Request` 構造体の `Form` フィールドは `url.Values` 型です。`url.Values` は `map[string][]string` のエイリアスであるため、そのゼロ値は `nil` です。

以前のテストコードでは、`Form: url.Values{},` と明示的に初期化されていました。これは、`Form` フィールドが `nil` ではなく、空の非`nil`マップであることを保証するためです。しかし、コミットメッセージの「empty is already not a nil.」という記述は、この明示的な初期化が不要になったことを示唆しています。

考えられる理由はいくつかあります。

1.  **Go言語のバージョンアップによる挙動変更**: Goの初期のバージョンでは、特定の状況下で構造体のマップフィールドが自動的に非`nil`の空マップとして初期化される挙動がなかったか、あるいはその挙動が不安定だった可能性があります。後のバージョンで、コンパイラやランタイムがより賢くなり、`Form` フィールドが使用される前に自動的に非`nil`の空マップとして扱われるようになったのかもしれません。
2.  **テストの要件変更**: テストのロジックが変更され、`Form` フィールドが `nil` であっても問題なく動作するように修正されたか、あるいは `Form` フィールドが `nil` であることを期待するようになった可能性があります。もしテストが `Form` フィールドに値を設定する前にアクセスしないのであれば、明示的な初期化は不要です。
3.  **冗長なコードの削除**: `url.Values{}` は空の非`nil`マップを作成しますが、もしテストが `Form` フィールドに何も追加せず、単にその存在をチェックするだけであれば、この初期化は冗長です。コードの簡潔化のために削除された可能性があります。

この変更は、テストコードの簡潔化と、Go言語のマップのゼロ値に関する理解の深化、またはGoコンパイラの進化を反映していると言えます。

### `Header: Header{},` の追加

`http.Request` および `http.Response` 構造体の `Header` フィールドは `http.Header` 型です。`http.Header` も `map[string][]string` のエイリアスであるため、そのゼロ値は `nil` です。

テストコードで `Header: Header{},` が追加されたのは、`Header` フィールドが `nil` のままだと問題が発生するためです。例えば、テスト内で `req.Header.Add("Content-Type", "text/plain")` のような操作を行おうとした場合、`req.Header` が `nil` だとパニックが発生します。

この修正は、以下のいずれかの状況を示唆しています。

1.  **テストの要件**: テストが `Header` フィールドが常に非`nil`のマップであることを期待しており、そのマップに対して何らかの操作(読み取り、書き込み)を行っている。
2.  **`net/http` パッケージの内部変更**: `net/http` パッケージの内部で、`Header` フィールドが非`nil`であることを前提とした処理が追加された。例えば、リクエストやレスポンスの処理中に、`Header` フィールドが `nil` でないことを前提としたアクセスが行われるようになったため、テストケースでもそれを反映する必要があった。
3.  **ビルドエラーの直接的な原因**: `Header` フィールドが `nil` のままであることが、コンパイル時またはリンク時にエラーを引き起こしていた。これは、Goのコンパイラが特定のコードパスで `Header` フィールドが非`nil`であることを期待するようになったためかもしれません。

この変更は、`Header` フィールドが `nil` の場合に発生する可能性のあるランタイムパニックやビルドエラーを防ぐための、必要な初期化であると言えます。

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

このコミットでは、以下の2つのテストファイルが変更されています。

1.  `src/pkg/net/http/readrequest_test.go`:
    *   `reqTests` スライス内の複数の `reqTest` 構造体定義から、`Form: url.Values{},` の行が削除されました。
    *   `reqTests` スライス内の2つの `reqTest` 構造体定義に、`Header: Header{},` の行が追加されました。
2.  `src/pkg/net/http/response_test.go`:
    *   `respTests` スライス内の2つの `respTest` 構造体定義に、`Header: Header{},` の行が追加されました。

## コアとなるコードの解説

### `src/pkg/net/http/readrequest_test.go` の変更

`readrequest_test.go` は、HTTPリクエストの読み込みとパースに関するテストケースを定義しています。

*   **`Form: url.Values{},` の削除**:
    これは、`reqTest` 構造体の `Form` フィールドの明示的な初期化を削除するものです。前述の通り、`url.Values{}` は空の非`nil`マップを作成します。この削除は、テストが `Form` フィールドが `nil` であっても問題なく動作するか、あるいは `Form` フィールドが自動的に非`nil`の空マップとして扱われるようになったことを示唆しています。これにより、テストコードがより簡潔になります。

*   **`Header: Header{},` の追加**:
    これは、`reqTest` 構造体の `Header` フィールドに `Header{}` を追加するものです。`Header{}` は空の非`nil`マップを作成します。この追加は、テストが `Header` フィールドが常に非`nil`のマップであることを期待しており、`nil` の場合に発生する可能性のあるパニックを防ぐために必要であったことを示しています。

### `src/pkg/net/http/response_test.go` の変更

`response_test.go` は、HTTPレスポンスの生成と処理に関するテストケースを定義しています。

*   **`Header: Header{},` の追加**:
    `respTests` スライス内の `respTest` 構造体定義に `Header: Header{},` が追加されました。これは `readrequest_test.go` の変更と同様に、レスポンスの `Header` フィールドが `nil` の場合に発生する可能性のある問題を回避するために、明示的に空の非`nil`マップとして初期化する必要があったことを示しています。

これらの変更は、Go言語のマップのゼロ値の挙動と、`net/http` パッケージの内部実装の進化に合わせて、テストコードの正確性と堅牢性を向上させるためのものです。特に、`Header` フィールドの初期化は、`nil` マップへのアクセスによるランタイムパニックを防ぐ上で重要です。

## 関連リンク

*   Go言語の公式ドキュメント: [https://golang.org/](https://golang.org/)
*   `net/http` パッケージのドキュメント: [https://pkg.go.dev/net/http](https://pkg.go.dev/net/http)
*   `net/url` パッケージのドキュメント: [https://pkg.go.dev/net/url](https://pkg.go.dev/net/url)
*   このコミットのGo CL (Code Review) ページ: [https://golang.org/cl/5376099](https://golang.org/cl/5376099)

## 参考にした情報源リンク

*   Go言語におけるマップのゼロ値と初期化に関する一般的な情報源 (例: Go言語の公式ブログ、Go言語の書籍、技術記事など)
*   `net/http` パッケージのソースコード (GoのGitHubリポジトリ)
*   `url.Values` および `http.Header` の実装詳細に関する情報源