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

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

このコミットは、Go言語の公式ドキュメントである effective_go.html および effective_go.tmpl 内のコード例から、未使用の変数を削除する修正です。具体的には、for...range ループでインデックス変数 i が宣言されているものの、その値がループ内で使用されていない箇所を特定し、インデックスを破棄する _ (ブランク識別子) に置き換えることで、Goコンパイラによる未使用変数エラー(または警告)を回避しています。

コミット

commit d1324d8a7a2a74b9eed8d62a28445db1bbdb90a9
Author: Rob Pike <r@golang.org>
Date:   Thu Nov 24 08:51:47 2011 -0800

    effective_go: remove unused variable from a couple of examples
    Fixes #2481.
    
    R=golang-dev, bradfitz
    CC=golang-dev
    https://golang.org/cl/5435068

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

https://github.com/golang/go/commit/d1324d8a7a2a74b9eed8d62a28445db1bbdb90a9

元コミット内容

effective_go: remove unused variable from a couple of examples (effective_go: いくつかの例から未使用変数を削除)

このコミットメッセージは、effective_go ドキュメント内のコード例に存在する未使用変数を修正したことを簡潔に示しています。Fixes #2481 は、このコミットがIssue 2481を解決したことを意味します。

変更の背景

Go言語は、宣言されたローカル変数が使用されない場合にコンパイルエラー(または警告)を発生させるという厳格なポリシーを持っています。これは、プログラマーが意図しない変数やデッドコードを残すことを防ぎ、コードの品質と可読性を高めるための設計思想です。

このコミットが行われた当時、effective_go ドキュメント内の ArgServer 関数を示すコード例において、for i, s := range os.Args のようにループインデックス i が宣言されていましたが、その i がループ本体内で実際に使用されていませんでした。このため、Goコンパイラは「i は宣言されたが使用されていない」というエラー(または警告)を報告していました。

ドキュメントのコード例は、読者がそのままコピー&ペーストして実行できるべきであり、コンパイルエラーが発生するべきではありません。この問題を解決し、ドキュメントの品質と正確性を保つために、この修正が導入されました。

前提知識の解説

Go言語の for...range ループ

Go言語の for...range ループは、スライス、配列、文字列、マップ、チャネルなどのコレクションをイテレートするための強力な構文です。

  • スライス/配列の場合: for index, value := range collection の形式で、各要素のインデックスと値を取得できます。
  • 文字列の場合: for index, runeValue := range string の形式で、各Unicodeコードポイント(rune)の開始バイトインデックスと値を取得できます。
  • マップの場合: for key, value := range map の形式で、各キーと値のペアを取得できます。

ブランク識別子 (_)

Go言語には、ブランク識別子 (_) と呼ばれる特別な識別子があります。これは、変数を宣言する際にその値を使用しないことを明示的に示すために使用されます。

例えば、for index, value := range collectionindex の値が必要ない場合、for _, value := range collection と書くことで、index が未使用であることによるコンパイルエラーを回避できます。これは、Goの厳格な未使用変数チェックをパスするための標準的な方法です。

未使用変数とGoコンパイラ

Goコンパイラは、宣言されたローカル変数が使用されない場合にエラーを発生させます。これは、C/C++などの言語では警告にとどまることが多いのに対し、Goではデフォルトでエラーとなる点が特徴です。この設計は、コードの意図を明確にし、潜在的なバグを防ぐのに役立ちます。

os.Args

os.Args は、Goプログラムが実行された際のコマンドライン引数を格納する文字列スライスです。os.Args[0] はプログラム自身のパス(または名前)であり、os.Args[1:] が実際の引数となります。

fmt.Printlnfmt.Fprintln

  • fmt.Println(a ...interface{}) (n int, err error): 引数を標準出力にスペース区切りで出力し、最後に改行を追加します。
  • fmt.Fprintln(w io.Writer, a ...interface{}) (n int, err error): 第一引数で指定された io.Writer インターフェースに引数を出力します。このコミットの例では http.ResponseWriterio.Writer インターフェースを満たしているため、HTTPレスポンスとして引数を出力するために使用されています。

effective_go ドキュメント

effective_go は、Go言語の公式ドキュメントの一部であり、Go言語を効果的に書くための慣用的なスタイル、パターン、およびヒントを提供します。これは、Goプログラマーがより良い、より効率的なコードを書くためのガイドラインとして広く参照されています。

技術的詳細

このコミットの技術的詳細は、Go言語の for...range ループと未使用変数に関する厳格なルールに集約されます。

元のコードでは、以下の形式でループが記述されていました。

for i, s := range os.Args {
    fmt.Println(s) // または fmt.Fprintln(w, s)
}

ここで、ios.Args スライスの各要素のインデックスを受け取る変数として宣言されています。しかし、ループ本体の fmt.Println(s)fmt.Fprintln(w, s) では、変数 s (要素の値) のみが使用されており、変数 i (インデックス) は全く使用されていませんでした。

Goコンパイラは、この i が宣言されたにもかかわらず使用されていないことを検出し、コンパイルエラーを発生させます。このエラーを解決するために、Goではブランク識別子 _ を使用して、特定の戻り値やループ変数を破棄する慣習があります。

修正後のコードは以下のようになります。

for _, s := range os.Args {
    fmt.Println(s) // または fmt.Fprintln(w, s)
}

i_ に置き換えることで、プログラマーは「このインデックスは必要ないため、意図的に無視する」という意思をコンパイラに伝えます。これにより、コンパイラは _ を未使用変数とは見なさず、エラーを発生させずにコードがコンパイルされるようになります。

この変更は、コードの振る舞いには一切影響を与えません。単に、Go言語のコンパイルルールに準拠させ、ドキュメントのコード例がエラーなく実行できるようにするための修正です。

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

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

  1. doc/effective_go.html
  2. doc/effective_go.tmpl

両ファイルにおいて、ArgServer という名前の関数内の for...range ループの記述が変更されています。

--- a/doc/effective_go.html
+++ b/doc/effective_go.html
@@ -2046,7 +2046,7 @@ It's easy to write a function to print the arguments.
 </p>
 <pre>
 func ArgServer() {
-    for i, s := range os.Args {
+    for _, s := range os.Args {
         fmt.Println(s)
     }\n
 }\n
@@ -2084,7 +2084,7 @@ to have the right signature.
 <pre>
 // Argument server.
 func ArgServer(w http.ResponseWriter, req *http.Request) {
-    for i, s := range os.Args {
+    for _, s := range os.Args {
         fmt.Fprintln(w, s)
     }\n
 }\n
--- a/doc/effective_go.tmpl
+++ b/doc/effective_go.tmpl
@@ -1984,7 +1984,7 @@ It's easy to write a function to print the arguments.
 </p>
 <pre>
 func ArgServer() {
-    for i, s := range os.Args {
+    for _, s := range os.Args {
         fmt.Println(s)
     }\n
 }\n
@@ -2022,7 +2022,7 @@ to have the right signature.
 <pre>
 // Argument server.
 func ArgServer(w http.ResponseWriter, req *http.Request) {
-    for i, s := range os.Args {
+    for _, s := range os.Args {
         fmt.Fprintln(w, s)
     }\n
 }\n

変更内容は、for i, s := range os.Argsi_ に置き換えることです。

コアとなるコードの解説

変更されたコードは、effective_go ドキュメント内でコマンドライン引数を処理する例として示されている ArgServer 関数です。

func ArgServer()

この関数は、コマンドライン引数を標準出力に1行ずつ出力するシンプルな例です。

func ArgServer() {
    for _, s := range os.Args { // 変更点: i を _ に変更
        fmt.Println(s)
    }
}

元のコードでは for i, s := range os.Args となっていましたが、インデックス ifmt.Println(s) の中で使用されていませんでした。この修正により、i がブランク識別子 _ に置き換えられ、未使用変数に関するコンパイルエラーが解消されました。

func ArgServer(w http.ResponseWriter, req *http.Request)

この関数は、HTTPリクエストのハンドラとして機能し、コマンドライン引数をHTTPレスポンスとしてクライアントに返す例です。

// Argument server.
func ArgServer(w http.ResponseWriter, req *http.Request) {
    for _, s := range os.Args { // 変更点: i を _ に変更
        fmt.Fprintln(w, s)
    }
}

こちらも同様に、for i, s := range os.Argsi がループ内で使用されていなかったため、_ に置き換えられました。fmt.Fprintln(w, s) は、w (HTTPレスポンスライター) に文字列 s を書き込むために使用されます。

これらの変更は、Go言語のベストプラクティスに従い、ドキュメントのコード例が常にコンパイル可能で、読者が学習しやすい状態を保つために重要です。

関連リンク

参考にした情報源リンク

  • Go言語の for...range ループに関する公式ドキュメントやチュートリアル
  • Go言語のブランク識別子 (_) に関する公式ドキュメントや解説
  • Go言語の未使用変数に関するコンパイラの挙動についての情報
  • os.Argsfmt.Printlnfmt.Fprintlnhttp.ResponseWriterhttp.Request のGo標準ライブラリドキュメント
  • effective_go ドキュメントの一般的な内容に関する知識