[インデックス 10601] ファイルの概要
このコミットは、Go言語の公式フォーマッタである gofmt
に -s
オプションを付けて misc
および src
ディレクトリ内のコードに適用した結果を反映しています。主な変更点は、複合リテラル(Composite Literals)の簡略化であり、冗長な &
演算子の削除が行われています。これにより、コードの可読性と一貫性が向上しています。
コミット
commit dcf1d7bc0e6146c143454dc5077de9452e6fd795
Author: Russ Cox <rsc@golang.org>
Date: Fri Dec 2 14:14:25 2011 -0500
gofmt -s misc src
R=golang-dev, bradfitz, gri
CC=golang-dev
https://golang.org/cl/5451079
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/dcf1d7bc0e6146c143454dc5077de9452e6fd795
元コミット内容
gofmt -s misc src
変更の背景
このコミットの背景には、Go言語のコードベース全体におけるコードスタイルの統一と可読性の向上が挙げられます。gofmt
はGo言語のコードを自動的にフォーマットするツールであり、Goコミュニティでは gofmt
によってフォーマットされたコードが標準とされています。-s
オプションは、コードをより簡潔にするための追加の簡略化(simplification)を適用します。
具体的には、このコミットは複合リテラルにおける冗長な &
演算子の削除を目的としています。Go言語では、構造体や配列、スライスなどの複合リテラルを初期化する際に、そのリテラルのアドレスを取得するために &
演算子を使用することがあります。しかし、コンパイラが型を推論できる場合や、リテラルが直接ポインタ型に代入される場合など、&
が冗長になるケースが存在します。gofmt -s
はこのような冗長な &
を自動的に削除し、コードをより簡潔に保ちます。
この変更は、Go言語の進化と、より洗練されたコードスタイルへの移行の一環として行われました。
前提知識の解説
gofmt
と gofmt -s
gofmt
: Go言語のソースコードを標準的なスタイルに自動的にフォーマットするツールです。インデント、スペース、改行などを統一し、Goコミュニティ全体で一貫したコードスタイルを維持するのに役立ちます。これにより、異なる開発者によって書かれたコードでも、同じ見た目と構造を持つことが保証され、コードレビューや共同作業が容易になります。gofmt -s
:gofmt
のオプションの一つで、コードの「簡略化 (simplify)」を行います。これは単なるフォーマット以上の変更であり、意味的に同じだがより簡潔な表現に書き換える機能です。例えば、今回のコミットで適用されている複合リテラルの&
削除などがこれに該当します。
Go言語の複合リテラル (Composite Literals)
Go言語では、構造体、配列、スライス、マップなどの複合型を初期化するために複合リテラルを使用します。
例:
type MyStruct struct {
Field1 int
Field2 string
}
// 構造体の複合リテラル
s := MyStruct{Field1: 10, Field2: "hello"}
// スライスの複合リテラル
arr := []int{1, 2, 3}
複合リテラルにおける &
演算子の簡略化
Go言語では、複合リテラルがポインタ型を期待するコンテキストで使用される場合、明示的に &
演算子を使ってリテラルのアドレスを取得する必要がありました。
例:
type Package struct {
Name string
Path string
}
// 以前の書き方: 明示的に & を使用
p := &Package{Name: "Go", Path: ""}
しかし、Goコンパイラは、複合リテラルがポインタ型に代入されることが明確な場合、&
演算子を省略してもそのリテラルのアドレスが取られることを推論できます。gofmt -s
はこの最適化を適用し、冗長な &
を削除します。
例:
// gofmt -s 適用後の書き方: & を省略
p := Package{Name: "Go", Path: ""} // この場合、p は *Package 型になる
この変更は、コードのセマンティクス(意味)を変えることなく、シンタックス(構文)を簡潔にするものです。
技術的詳細
このコミットで行われた変更は、Go言語のコードベース全体にわたる広範なリファクタリングです。gofmt -s
ツールが実行され、Go言語の複合リテラルにおける冗長な &
演算子が削除されました。
具体的には、以下のようなパターンが変更されています。
&Type{...}
->{...}
- これは、
Type
が構造体であり、その複合リテラルがポインタ型(*Type
)を期待する変数に代入される場合に適用されます。コンパイラは、このコンテキストで&
が必要であることを自動的に推論できるため、明示的な&
は冗長と見なされます。
- これは、
[]*Type{&Type{...}, &Type{...}}
->[]*Type{{...}, {...}}
- スライスや配列の要素としてポインタ型の複合リテラルが使用される場合も同様です。各要素の
&
が削除されます。
- スライスや配列の要素としてポインタ型の複合リテラルが使用される場合も同様です。各要素の
この変更の技術的な利点は以下の通りです。
- コードの簡潔性向上: 冗長な記号が減ることで、コードがより読みやすくなります。特に、ネストされた複合リテラルや長い初期化リストにおいて、この簡略化は大きな効果を発揮します。
- 一貫性の強化:
gofmt -s
を通じて自動的に適用されるため、コードベース全体で複合リテラルの記述スタイルが一貫します。これにより、新しいコードを書く際にも迷いがなくなり、コードレビューの負担も軽減されます。 - パフォーマンスへの影響なし: この変更はコンパイル時に解決される構文上の簡略化であり、生成されるバイナリコードのパフォーマンスには影響を与えません。コンパイラは
&
が存在しない場合でも、必要に応じてアドレスを取得するコードを生成します。
このコミットは、Go言語の設計哲学である「シンプルさ」と「明瞭さ」を追求する典型的な例と言えます。ツールによる自動化されたリファクタリングは、大規模なコードベースの品質を維持する上で非常に有効な手段です。
コアとなるコードの変更箇所
このコミットは多数のファイルにわたる変更ですが、その性質は一貫しています。以下に代表的な変更箇所をいくつか示します。
misc/dashboard/app/build/test.go
--- a/misc/dashboard/app/build/test.go
+++ b/misc/dashboard/app/build/test.go
@@ -36,7 +36,7 @@ const testPkg = "code.google.com/p/go.more"
var testPackage = &Package{Name: "Test", Path: testPkg}
var testPackages = []*Package{
- &Package{Name: "Go", Path: ""},
+ {Name: "Go", Path: ""},
testPackage,
}
testPackages
スライス内の &Package{...}
が {...}
に変更されています。
src/cmd/cgo/out.go
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -578,22 +578,22 @@ func c(repr string, args ...interface{}) *TypeRepr {
// Map predeclared Go types to Type.
var goTypes = map[string]*Type{
- "int": &Type{Size: 4, Align: 4, C: c("int")},
- "uint": &Type{Size: 4, Align: 4, C: c("uint")},
- "int8": &Type{Size: 1, Align: 1, C: c("schar")},
- "uint8": &Type{Size: 1, Align: 1, C: c("uchar")},
- "int16": &Type{Size: 2, Align: 2, C: c("short")},
- "uint16": &Type{Size: 2, Align: 2, C: c("ushort")},
- "int32": &Type{Size: 4, Align: 4, C: c("int")},
- "uint32": &Type{Size: 4, Align: 4, C: c("uint")},
- "int64": &Type{Size: 8, Align: 8, C: c("int64")},
- "uint64": &Type{Size: 8, Align: 8, C: c("uint64")},
- "float": &Type{Size: 4, Align: 4, C: c("float")},
- "float32": &Type{Size: 4, Align: 4, C: c("float")},
- "float64": &Type{Size: 8, Align: 8, C: c("double")},
- "complex": &Type{Size: 8, Align: 8, C: c("__complex float")},
- "complex64": &Type{Size: 8, Align: 8, C: c("__complex float")},
- "complex128": &Type{Size: 16, Align: 16, C: c("__complex double")},
+ "int": {Size: 4, Align: 4, C: c("int")},
+ "uint": {Size: 4, Align: 4, C: c("uint")},
+ "int8": {Size: 1, Align: 1, C: c("schar")},
+ "uint8": {Size: 1, Align: 1, C: c("uchar")},
+ "int16": {Size: 2, Align: 2, C: c("short")},
+ "uint16": {Size: 2, Align: 2, C: c("ushort")},
+ "int32": {Size: 4, Align: 4, C: c("int")},
+ "uint32": {Size: 4, Align: 4, C: c("uint")},
+ "int64": {Size: 8, Align: 8, C: c("int64")},
+ "uint64": {Size: 8, Align: 8, C: c("uint64")},
+ "float": {Size: 4, Align: 4, C: c("float")},
+ "float32": {Size: 4, Align: 4, C: c("float")},
+ "float64": {Size: 8, Align: 8, C: c("double")},
+ "complex": {Size: 8, Align: 8, C: c("__complex float")},
+ "complex64": {Size: 8, Align: 8, C: c("__complex float")},
+ "complex128": {Size: 16, Align: 16, C: c("__complex double")},
}
goTypes
マップの初期化において、&Type{...}
が {...}
に変更されています。
src/pkg/archive/tar/reader_test.go
--- a/src/pkg/archive/tar/reader_test.go
+++ b/src/pkg/archive/tar/reader_test.go
@@ -24,7 +24,7 @@ type untarTest struct {
var gnuTarTest = &untarTest{
file: "testdata/gnu.tar",
headers: []*Header{
- &Header{
+ {
Name: "small.txt",
Mode: 0640,
Uid: 73025,
@@ -35,7 +35,7 @@ var gnuTarTest = &untarTest{
Uname: "dsymonds",
Gname: "eng",
},
- &Header{
+ {
Name: "small2.txt",
Mode: 0640,
Uid: 73025,
@@ -55,10 +55,10 @@ var gnuTarTest = &untarTest{
var untarTests = []*untarTest{
gnuTarTest,
- &untarTest{
+ {
file: "testdata/star.tar",
headers: []*Header{
- &Header{
+ {
Name: "small.txt",
Mode: 0640,
Uid: 73025,
@@ -71,7 +71,7 @@ var untarTests = []*untarTest{
AccessTime: time.Unix(1244592783, 0),
ChangeTime: time.Unix(1244592783, 0),
},
- &Header{
+ {
Name: "small2.txt",
Mode: 0640,
Uid: 73025,
@@ -86,10 +86,10 @@ var untarTests = []*untarTest{
},
},
},
- &untarTest{
+ {
file: "testdata/v7.tar",
headers: []*Header{
- &Header{
+ {
Name: "small.txt",
Mode: 0444,
Uid: 73025,
@@ -98,7 +98,7 @@ var untarTests = []*untarTest{
ModTime: time.Unix(1244593104, 0),
Typeflag: '\x00',
},
- &Header{
+ {
Name: "small2.txt",
Mode: 0444,
Uid: 73025,
テストデータ内の &Header{...}
や &untarTest{...}
が {...}
に変更されています。
コアとなるコードの解説
これらの変更は、Go言語の複合リテラルがポインタ型を生成する際に、明示的な &
演算子が不要になるケースを gofmt -s
が自動的に検出して削除したものです。
例えば、misc/dashboard/app/build/test.go
の変更では、testPackages
という []*Package
型のスライスを初期化しています。このスライスは *Package
型の要素を期待しているため、Package{Name: "Go", Path: ""}
という複合リテラルは自動的に *Package
型の値(つまり、Package
構造体のアドレス)として扱われます。したがって、&
を明示的に記述する必要がなくなります。
同様に、src/cmd/cgo/out.go
の goTypes
マップの初期化や、src/pkg/archive/tar/reader_test.go
のテストデータ初期化においても、複合リテラルがポインタ型を期待するコンテキストで使用されているため、&
が省略されています。
この簡略化は、コードの見た目をすっきりとさせ、冗長性を排除することで、Go言語のコードがより「Goらしい」スタイルに近づくことを意味します。開発者は、ポインタが必要な場合に常に &
を書くのではなく、コンパイラが型を推論できる場合は省略できるというGo言語の柔軟性を享受できます。
関連リンク
- Go言語の公式ドキュメント: https://golang.org/doc/
gofmt
のドキュメント (Goコマンドの一部として): https://golang.org/cmd/go/#hdr-Gofmt_files- Go言語の複合リテラルに関する公式ブログ記事 (関連情報): https://blog.golang.org/go-slices-usage-and-internals (スライスに関する記事ですが、複合リテラルの概念も含まれます)
参考にした情報源リンク
- Go言語の公式ドキュメント
gofmt
のマニュアルページ- Go言語の複合リテラルに関する一般的な知識
- Go言語のポインタに関する一般的な知識
- GitHub上のGo言語リポジトリのコミット履歴