[インデックス 14079] ファイルの概要
コミット
commit 7f710c2de99b747fe98111c1aa143365c615e4ba
Author: Robert Griesemer <gri@golang.org>
Date: Sun Oct 7 17:59:33 2012 -0700
exp/locale/collate: use gofmt -w -s (rather than just gofmt -w)
Also: apply gofmt -w -s to existing tables.
R=mpvl, minux.ma, rsc
CC=golang-dev
https://golang.org/cl/6611051
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/7f710c2de99b747fe98111c1aa143365c615e4ba
元コミット内容
exp/locale/collate: use gofmt -w -s (rather than just gofmt -w)
Also: apply gofmt -w -s to existing tables.
R=mpvl, minux.ma, rsc
CC=golang-dev
https://golang.org/cl/6611051
変更の背景
このコミットは、Go言語の実験的なロケール照合(exp/locale/collate
)パッケージにおいて、コードフォーマットツールであるgofmt
の利用方法を改善することを目的としています。具体的には、単にコードを整形するgofmt -w
ではなく、より簡潔なコードを生成するgofmt -w -s
を使用するように変更しています。さらに、既存のテーブルファイルにもこの新しいフォーマットルールを適用することで、コードベース全体の一貫性と可読性を向上させています。
背景としては、Go言語のプロジェクトではgofmt
による自動フォーマットが強く推奨されており、コードの一貫性を保つ上で非常に重要なツールです。gofmt
は、単にインデントやスペースを調整するだけでなく、Goの言語仕様に基づいた構文的な簡略化(simplification)も行うことができます。このコミットは、その簡略化機能を活用することで、冗長なコードを削減し、よりクリーンで保守しやすいコードを目指したものです。特に、exp/locale/collate
パッケージはロケールデータを含むテーブルファイルを多く扱っており、これらのファイルに簡略化を適用することで、ファイルサイズや読み込み時のパフォーマンスにも間接的に影響を与える可能性があります。
前提知識の解説
Go言語 (Go
)
GoはGoogleによって開発されたオープンソースのプログラミング言語です。静的型付け、コンパイル型言語でありながら、動的型付け言語のような開発のしやすさを目指しています。並行処理を強力にサポートするgoroutineとchannel、高速なコンパイル、シンプルな構文が特徴です。
gofmt
gofmt
はGo言語のソースコードを自動的にフォーマットするツールです。Goのツールチェインに標準で含まれており、Goコミュニティではgofmt
によるコードフォーマットが強く推奨されています。これにより、プロジェクト内のすべてのGoコードが統一されたスタイルで記述され、可読性と保守性が向上します。
gofmt -w
:-w
オプションは、フォーマット結果を元のファイルに書き戻す(write)ことを意味します。このオプションがない場合、gofmt
はフォーマット結果を標準出力に出力します。gofmt -s
:-s
オプションは、コードを簡略化(simplify)する機能を提供します。これは、冗長な構文をより簡潔な形式に変換するものです。例えば、スライスやマップのリテラル初期化において、型情報を省略できる場合にそれを自動的に削除するなどの処理を行います。
ロケール (Locale
)
ロケールとは、言語、国、文字セット、日付や時刻の表示形式、通貨記号など、ユーザーの地域や文化に合わせた設定の集合体を指します。ソフトウェアが異なる地域や言語のユーザーに対応するために、ロケール情報が利用されます。
照合 (Collation
)
照合とは、文字列を特定のルールに基づいて比較し、順序付けするプロセスです。これは、辞書順ソートや検索において非常に重要です。言語によって文字の並び順や、アクセント記号、合字(ligature)などの扱いが異なるため、ロケールに応じた照合ルールが必要となります。exp/locale/collate
パッケージは、Go言語で国際化された文字列照合機能を提供するための実験的なパッケージです。
Makefile
Makefile
は、make
ユーティリティがプログラムのコンパイルやその他のタスクを自動化するために使用するファイルです。Makefile
には、ターゲット(生成されるファイル)と、そのターゲットを生成するために必要な依存関係とコマンドが記述されます。このコミットでは、Makefile
内のgofmt
コマンドの呼び出しが変更されています。
技術的詳細
このコミットの主要な技術的変更点は、gofmt
コマンドに-s
オプションを追加したことです。
gofmt -s
は、Goのコードベースにおいて以下のような簡略化を自動的に適用します。
-
複合リテラルの簡略化:
[]int{}
のようなスライスリテラルや、map[string]string{}
のようなマップリテラルで、要素の型がコンテキストから推論できる場合、型名を省略して{}
と記述できるようになります。- 例:
[]int{1, 2, 3}
が{1, 2, 3}
に、map[string]string{"key": "value"}
が{"key": "value"}
に簡略化されます。 - このコミットの差分を見ると、
src/pkg/exp/locale/collate/build/builder_test.go
やsrc/pkg/exp/locale/collate/tables.go
で、[]int{}
やtableIndex{}
のような複合リテラルから型情報が削除されているのが確認できます。これは、gofmt -s
が適用された結果です。
-
for
ループの簡略化:for key, _ := range collection
のように、インデックスや値が不要な場合に_
を使用しているループで、_
を省略できる場合があります。- このコミットでは、
src/pkg/exp/locale/collate/maketables.go
でfor j, _ := range c.Rules.Any
がfor j := range c.Rules.Any
に変更されています。これは、j
のみが必要で、_
で受け取っていた値が不要になったため、_
を省略した形です。
これらの変更は、コードの冗長性を減らし、よりGoらしい(idiomatic Go)記述に近づけることを目的としています。特に、exp/locale/collate
パッケージ内のテーブルデータは、構造体やスライスのリテラルで大量に定義されているため、-s
オプションの適用はコードの行数を減らし、視覚的なノイズを削減する効果があります。
Makefile
の変更は、この新しいgofmt
の振る舞いをビルドプロセスに組み込むためのものです。maketables
ターゲットがtables.go
を生成した後、以前はgofmt -w tables.go
を実行していましたが、これをgofmt -w -s tables.go
に変更することで、生成されるテーブルファイルが自動的に簡略化された形式でフォーマットされるようになります。同様に、src/pkg/exp/locale/collate/tools/colcmp/Makefile
内のchars
ターゲットでも、生成されるchars.go
に対してgofmt -w -s
が適用されるように変更されています。
この変更は、機能的な変更ではなく、コードのスタイルと保守性に関する改善です。しかし、大規模なコードベースにおいて、このような自動化された簡略化は、コードレビューの負担を軽減し、開発者がより本質的なロジックに集中できる環境を提供します。
コアとなるコードの変更箇所
このコミットにおけるコアとなるコードの変更は、主に以下のファイルに見られます。
src/pkg/exp/locale/collate/Makefile
:tables:
ターゲットにおいて、gofmt -w tables.go
がgofmt -w -s tables.go
に変更されました。
src/pkg/exp/locale/collate/build/builder_test.go
:- スライスリテラルの初期化において、
[]int{...}
の形式が{...}
に簡略化されました。 - 例:
[]int{base + int(r>>15), defaultSecondary, defaultTertiary, int(r)}
が{base + int(r>>15), defaultSecondary, defaultTertiary, int(r)}
に変更。
- スライスリテラルの初期化において、
src/pkg/exp/locale/collate/build/contract_test.go
:- 同様に、スライスリテラルの初期化において、
[]stridx{...}
やcontractTrieSet{...}
の形式が{...}
に簡略化されました。
- 同様に、スライスリテラルの初期化において、
src/pkg/exp/locale/collate/build/order.go
:- スライスリテラルの初期化において、
[]int{...}
の形式が{...}
に簡略化されました。
- スライスリテラルの初期化において、
src/pkg/exp/locale/collate/maketables.go
:for j, _ := range c.Rules.Any
のようなfor
ループがfor j := range c.Rules.Any
に簡略化されました。
src/pkg/exp/locale/collate/tables.go
:map[string]tableIndex
の初期化において、tableIndex{...}
の形式が{...}
に簡略化されました。このファイルはロケールデータテーブルを大量に含んでいるため、この変更が最も多くの行に影響を与えています。
src/pkg/exp/locale/collate/tools/colcmp/Makefile
:chars:
ターゲットにおいて、gofmt -w chars.go
がgofmt -w -s chars.go
に変更されました。
src/pkg/exp/locale/collate/tools/colcmp/chars.go
:- マップリテラルの初期化において、
[exN]string{...}
の形式が{...}
に簡略化されました。
- マップリテラルの初期化において、
これらの変更は、gofmt -s
の適用によって自動的に行われるコードの簡略化を反映しています。
コアとなるコードの解説
このコミットの核心は、Goの標準フォーマッタであるgofmt
の-s
オプションの導入と、それによるコードの自動簡略化です。
Makefile
の変更
Makefile
の変更は、ビルドプロセスにgofmt -s
を組み込むためのものです。
--- a/src/pkg/exp/locale/collate/Makefile
+++ b/src/pkg/exp/locale/collate/Makefile
@@ -9,7 +9,7 @@ maketables: maketables.go
tables: maketables
./maketables > tables.go
- gofmt -w tables.go
+ gofmt -w -s tables.go
この変更により、tables.go
というファイルがmaketables
コマンドによって生成された後、そのファイルに対してgofmt -w -s
が実行されます。-w
は変更をファイルに書き戻すことを意味し、-s
はコードを簡略化します。これにより、生成されるテーブルファイルが常に簡潔な形式でフォーマットされることが保証されます。同様の変更がsrc/pkg/exp/locale/collate/tools/colcmp/Makefile
にも適用されています。
複合リテラルの簡略化
gofmt -s
の最も顕著な効果は、複合リテラル(composite literal)の簡略化です。これは、スライス、配列、マップ、構造体の初期化において、型情報がコンテキストから推論できる場合に、その型名を省略できるというGoの言語機能を利用したものです。
例えば、src/pkg/exp/locale/collate/build/builder_test.go
では、以下のような変更が見られます。
--- a/src/pkg/exp/locale/collate/build/builder_test.go
+++ b/src/pkg/exp/locale/collate/build/builder_test.go
@@ -14,29 +14,29 @@ func cjk(r rune) [][]int {
// Any base value will work for the test, so we pick the common value of FB40.
const base = 0xFB40
return [][]int{
- []int{base + int(r>>15), defaultSecondary, defaultTertiary, int(r)},
- []int{int(r&0x7FFF) | 0x8000, 0, 0, int(r)},
+ {base + int(r>>15), defaultSecondary, defaultTertiary, int(r)},
+ {int(r&0x7FFF) | 0x8000, 0, 0, int(r)},
}
}
func pCE(p int) [][]int {
- return [][]int{[]int{p, defaultSecondary, defaultTertiary, 0}}
+ return [][]int{{p, defaultSecondary, defaultTertiary, 0}}
}
func pqCE(p, q int) [][]int {
- return [][]int{[]int{p, defaultSecondary, defaultTertiary, q}}
+ return [][]int{{p, defaultSecondary, defaultTertiary, q}}
}
func ptCE(p, t int) [][]int {
- return [][]int{[]int{p, defaultSecondary, t, 0}}
+ return [][]int{{p, defaultSecondary, t, 0}}
}
func sCE(s int) [][]int {
- return [][]int{[]int{0, s, defaultTertiary, 0}}
+ return [][]int{{0, s, defaultTertiary, 0}}
}
func stCE(s, t int) [][]int {
- return [][]int{[]int{0, s, t, 0}}
+ return [][]int{{0, s, t, 0}}
}
ここでは、[]int{...}
の部分が {...}
に変更されています。これは、[][]int
という外側のスライス型から、内側の要素が[]int
であることが明確に推論できるため、冗長な型指定を省略できるためです。
同様に、src/pkg/exp/locale/collate/tables.go
では、map[string]tableIndex
の初期化において、tableIndex{...}
が{...}
に簡略化されています。
--- a/src/pkg/exp/locale/collate/tables.go
+++ b/src/pkg/exp/locale/collate/tables.go
@@ -8,311 +8,311 @@ package collate
var availableLocales = []string{\"af\", \"ar\", \"as\", \"az\", \"be\", \"bg\", \"bn\", \"ca\", \"cs\", \"cy\", \"da\", \"de\", \"dz\", \"el\", \"en_US_POSIX\", \"eo\", \"es\", \"et\", \"fa\", \"fi\", \"fil\", \"fo\", \"fr_CA\", \"gu\", \"ha\", \"haw\", \"he\", \"hi\", \"hr\", \"hu\", \"hy\", \"ig\", \"is\", \"ja\", \"kk\", \"kl\", \"km\", \"kn\", \"ko\", \"kok\", \"ln\", \"lt\", \"lv\", \"mk\", \"ml\", \"mr\", \"mt\", \"my\", \"nb\", \"nn\", \"nso\", \"om\", \"or\", \"pa\", \"pl\", \"ps\", \"ro\", \"root\", \"ru\", \"se\", \"si\", \"sk\", \"sl\", \"sq\", \"sr\", \"sv\", \"ta\", \"te\", \"th\", \"tn\", \"tr\", \"uk\", \"ur\", \"vi\", \"wae\", \"yo\", \"zh\"}\n \n var locales = map[string]tableIndex{\n-\t\"af\": tableIndex{\n+\t\"af\": {\n \t\tlookupOffset: 0x13,\n \t\tvaluesOffset: 0x0,\n \t},\
これは、locales
マップのキーがstring
で、値がtableIndex
型であることが宣言されているため、各要素の初期化時にtableIndex
という型名を再度記述する必要がないためです。
for
ループの簡略化
src/pkg/exp/locale/collate/maketables.go
では、for
ループの簡略化が行われています。
--- a/src/pkg/exp/locale/collate/maketables.go
+++ b/src/pkg/exp/locale/collate/maketables.go
@@ -562,7 +562,7 @@ func parseCollation(b *build.Builder) {
if c.Alt != "" && skipAlt(c.Alt) {
continue
}
- for j, _ := range c.Rules.Any {
+ for j := range c.Rules.Any {
c.Rules.Any[j].rewrite()
}
locale := lang
元のコードではfor j, _ := range c.Rules.Any
と記述されており、range
キーワードが返す2番目の値(この場合はc.Rules.Any
の要素自体)が_
(ブランク識別子)で破棄されていました。これは、ループ内でインデックスj
のみが必要で、要素の値は使用しないことを示しています。gofmt -s
は、このような場合に_
を完全に省略してfor j := range c.Rules.Any
と記述することを推奨します。これにより、コードがより簡潔になり、開発者の意図(要素の値は不要であること)がより明確になります。
これらの変更は、Go言語のイディオムに沿ったコードスタイルを強制し、コードベース全体の一貫性と保守性を高めるためのものです。機能的な変更は含まれていませんが、コードの品質向上に寄与しています。
関連リンク
参考にした情報源リンク
- golang/go GitHub Repository
- Go Code Review Comments: Blank identifier
- Go Code Review Comments: Composite literals
- Go言語のgofmtコマンドについて - Qiita (これは一般的な
gofmt
の解説として参照しました) - Go言語のgofmt -sオプションについて - Zenn (これは
-s
オプションの具体的な挙動を理解するために参照しました) - Go言語のgofmt -sオプションでコードを簡潔にする - Speaker Deck (これも
-s
オプションの具体的な挙動を理解するために参照しました)