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

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

このコミットは、Go言語の標準ツールであるgofmtsrcおよびmiscディレクトリ以下のファイルに対して実行し、コードのフォーマットを統一したものです。特に、構造体リテラルの初期化における&演算子の省略と、for rangeループにおけるインデックスのみの使用に焦点を当てた変更が含まれています。

コミット

commit 56cae1c2307be5895c628b66f7b2418d56278f98
Author: Robert Griesemer <gri@golang.org>
Date:   Thu Mar 8 10:48:51 2012 -0800

    all: gofmt -w -s src misc
    
    R=golang-dev, rsc
    CC=golang-dev
    https://golang.org/cl/5781058

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

https://github.com/golang/go/commit/56cae1c2307be5895c628b66f7b2418d56278f98

元コミット内容

all: gofmt -w -s src misc

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

変更の背景

このコミットの主な目的は、Go言語のコードベース全体で一貫したコーディングスタイルを強制することです。gofmtはGo言語の公式なフォーマッタであり、コードの可読性を高め、スタイルに関する議論を減らすために設計されています。特に-sオプションは、より簡潔なコードを生成するための簡略化(simplification)を適用します。このコミットは、Go言語の進化に伴い、より新しい、より簡潔な構文が推奨されるようになったことを反映しています。具体的には、構造体リテラルでポインタを生成する際の&の省略や、for rangeループで値を使用しない場合の_の省略が挙げられます。これにより、コードの冗長性が減り、よりGoらしい(idiomatic Go)記述に近づきます。

前提知識の解説

gofmtとは

gofmtは、Go言語のソースコードを自動的にフォーマットするツールです。Go言語のツールチェインに標準で含まれており、Goコミュニティ全体で一貫したコーディングスタイルを維持するために広く利用されています。gofmtは、インデント、スペース、改行などの基本的なフォーマットだけでなく、特定のコードパターンをより簡潔な形式に書き換える「簡略化(simplification)」機能も持っています。

gofmtのオプション

  • -w: フォーマット結果を元のファイルに書き込みます。このオプションがない場合、gofmtはフォーマット結果を標準出力に出力します。
  • -s: コードを簡略化(simplify)します。これは、より簡潔で慣用的なGoの書き方に変換する機能です。このコミットでは、特に以下の2つの簡略化が適用されています。
    1. 構造体リテラルにおける&の省略: Go 1から、構造体リテラルを初期化する際に、その構造体のポインタを返す場合、&StructType{...}のように&を明示的に記述する必要がなくなりました。代わりにStructType{...}と記述するだけで、コンパイラが自動的にポインタを生成します。これは、構造体リテラルが直接ポインタ型として使用される文脈(例: スライスやマップの要素、関数の引数など)で有効です。
    2. for rangeループにおける_の省略: for rangeループでインデックスと値の両方を受け取る場合、for i, v := range collectionのように記述します。しかし、インデックスのみが必要で値が不要な場合、以前はfor i, _ := range collectionのように値を_(ブランク識別子)で破棄していました。Go 1.4以降、インデックスのみが必要な場合はfor i := range collectionと記述するだけでよくなりました。これにより、不要な_を記述する必要がなくなり、コードがより簡潔になります。

Go言語の慣用的な書き方 (Idiomatic Go)

Go言語には、コミュニティで広く受け入れられている特定のコーディングスタイルやパターンがあります。これを「慣用的なGo(Idiomatic Go)」と呼びます。gofmtは、この慣用的なスタイルを自動的に適用することで、Goコードの可読性と保守性を高めるのに貢献しています。このコミットで行われた変更は、当時のGo言語の慣用的な書き方に合わせてコードベースを更新する作業の一環です。

技術的詳細

このコミットは、gofmt -w -s src miscコマンドの実行結果を反映しています。具体的には、以下の2種類のコード簡略化が広範囲に適用されています。

  1. 構造体リテラルの&演算子省略:

    • 変更前: &Package{Name: "Go", Kind: "go"}
    • 変更後: {Name: "Go", Kind: "go"} これは、構造体リテラルがポインタ型として使用される文脈において、&演算子を省略できるようになったGoの言語仕様の変更(または推奨されるスタイル)を反映しています。コンパイラが文脈からポインタが必要であることを判断し、自動的にポインタを生成します。これにより、コードがより簡潔になります。
  2. for rangeループにおけるブランク識別子_の省略:

    • 変更前: for i, _ := range peers
    • 変更後: for i := range peers これは、for rangeループでインデックスのみが必要で、値が不要な場合に、ブランク識別子_を明示的に記述する必要がなくなったことを反映しています。Go 1.4以降、インデックスのみが必要な場合はfor i := range collectionと記述することが推奨されています。これにより、コードの冗長性が排除されます。

これらの変更は、機能的な振る舞いには影響を与えません。純粋にコードのスタイルと簡潔性を向上させるためのものです。gofmt -sは、このような簡略化を自動的に識別し、適用する能力を持っています。

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

このコミットでは、複数のファイルにわたって同様のパターンで変更が加えられています。以下に主要な変更箇所を抜粋し、そのパターンを示します。

misc/dashboard/app/build/init.go および misc/dashboard/app/build/test.go

--- a/misc/dashboard/app/build/init.go
+++ b/misc/dashboard/app/build/init.go
@@ -15,7 +15,7 @@ import (
 
 // defaultPackages specifies the Package records to be created by initHandler.
 var defaultPackages = []*Package{
-	&Package{Name: "Go", Kind: "go"},
+	{Name: "Go", Kind: "go"},
 }
 
 // subRepos specifies the Go project sub-repositories.
--- a/misc/dashboard/app/build/test.go
+++ b/misc/dashboard/app/build/test.go
@@ -37,7 +37,7 @@ const testPkg = "code.google.com/p/go.test"
 var testPackage = &Package{Name: "Test", Kind: "subrepo", Path: testPkg}
 
 var testPackages = []*Package{
-	&Package{Name: "Go", Path: ""},
+	{Name: "Go", Path: ""},
 	testPackage,
 }
 

ここでは、&Package{...}という構造体リテラルの初期化が、{...}という形式に簡略化されています。これは、defaultPackagestestPackages[]*Package型(Package構造体へのポインタのスライス)であるため、コンパイラが自動的にポインタを生成できる文脈であるためです。

src/pkg/crypto/tls/handshake_server_test.go および src/pkg/exp/norm/maketables.go

--- a/src/pkg/crypto/tls/handshake_server_test.go
+++ b/src/pkg/crypto/tls/handshake_server_test.go
@@ -143,7 +143,7 @@ func testServerScript(t *testing.T, name string, serverScript [][]byte, config *
 	if peers != nil {
 		gotpeers := <-pchan
 		if len(peers) == len(gotpeers) {
-			for i, _ := range peers {
+			for i := range peers {
 				if !peers[i].Equal(gotpeers[i]) {
 					t.Fatalf("%s: mismatch on peer cert %d", name, i)
 				}
--- a/src/pkg/exp/norm/maketables.go
+++ b/src/pkg/exp/norm/maketables.go
@@ -577,7 +577,7 @@ type decompSet [4]map[string]bool
 
 func makeDecompSet() decompSet {
 	m := decompSet{}
-	for i, _ := range m {
+	for i := range m {
 		m[i] = make(map[string]bool)
 	}
 	return m
@@ -646,7 +646,7 @@ func printCharInfoTables() int {
 	fmt.Println("const (")
 	for i, m := range decompSet {
 		sa := []string{}
-		for s, _ := range m {
+		for s := range m {
 			sa = append(sa, s)
 		}
 		sort.Strings(sa)

これらの変更では、for rangeループでインデックスiのみが使用され、値が使用されていない箇所で、ブランク識別子_が省略されています。for i, _ := range collectionfor i := range collectionに簡略化されています。

src/pkg/database/sql/sql_test.go

このファイルでは、nullTestRow構造体の初期化において、nullTestRow{...}{...}に簡略化されています。これは、nullTestRowが配列の要素として直接使用されており、その文脈でポインタが不要であるため、構造体リテラルの&が省略されたものと考えられます。

--- a/src/pkg/database/sql/sql_test.go
+++ b/src/pkg/database/sql/sql_test.go
@@ -463,48 +463,48 @@ type nullTestSpec struct {
 
 func TestNullStringParam(t *testing.T) {
 	spec := nullTestSpec{"nullstring", "string", [6]nullTestRow{
-		nullTestRow{NullString{"aqua", true}, "", NullString{"aqua", true}},
-		nullTestRow{NullString{"brown", false}, "", NullString{"", false}},
-		nullTestRow{"chartreuse", "", NullString{"chartreuse", true}},
-		nullTestRow{NullString{"darkred", true}, "", NullString{"darkred", true}},
-		nullTestRow{NullString{"eel", false}, "", NullString{"", false}},
-		nullTestRow{"foo", NullString{"black", false}, nil},
+		{NullString{"aqua", true}, "", NullString{"aqua", true}},
+		{NullString{"brown", false}, "", NullString{"", false}},
+		{"chartreuse", "", NullString{"chartreuse", true}},
+		{NullString{"darkred", true}, "", NullString{"darkred", true}},
+		{NullString{"eel", false}, "", NullString{"", false}},
+		{"foo", NullString{"black", false}, nil},
 	}}
 	nullTestRun(t, spec)
 }

コアとなるコードの解説

このコミットにおけるコードの変更は、Go言語のgofmt -sコマンドによって自動的に適用される「簡略化」の典型例です。

  1. 構造体リテラルの&省略: Go言語では、構造体リテラルを初期化する際に、その構造体のポインタが必要な文脈(例: []*MyStructのようなポインタのスライスに要素を追加する場合)では、&MyStruct{...}と記述することでポインタを生成します。しかし、Goのコンパイラは賢く、文脈からポインタが必要であることを推論できる場合、&を省略してMyStruct{...}と記述することを許可しています。この簡略化は、コードの視覚的なノイズを減らし、より簡潔な記述を可能にします。このコミットでは、Package構造体のポインタのスライスを初期化する際に、この簡略化が適用されています。

  2. for rangeループにおける_の省略: for rangeループは、スライス、配列、文字列、マップ、チャネルなどのコレクションをイテレートするために使用されます。通常、for index, value := range collectionのように、インデックスと値の両方を受け取ります。しかし、インデックスのみが必要で値が不要な場合、またはその逆の場合、不要な要素をブランク識別子_で破棄することが一般的でした(例: for i, _ := range collection)。Go 1.4以降、インデックスのみが必要な場合はfor i := range collectionと記述することが、より慣用的なスタイルとして推奨されるようになりました。これにより、コードの意図がより明確になり、不要な_の記述が削減されます。このコミットでは、複数のテストファイルやユーティリティファイルで、この簡略化が適用されています。

これらの変更は、Go言語の進化と、よりクリーンで慣用的なコードを奨励するgofmtの役割を明確に示しています。機能的な変更は一切なく、純粋にコードの見た目とスタイルに関する改善です。

関連リンク

参考にした情報源リンク