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

[インデックス 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のコードベースにおいて以下のような簡略化を自動的に適用します。

  1. 複合リテラルの簡略化:

    • []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.gosrc/pkg/exp/locale/collate/tables.go で、[]int{}tableIndex{} のような複合リテラルから型情報が削除されているのが確認できます。これは、gofmt -sが適用された結果です。
  2. forループの簡略化:

    • for key, _ := range collection のように、インデックスや値が不要な場合に_を使用しているループで、_を省略できる場合があります。
    • このコミットでは、src/pkg/exp/locale/collate/maketables.gofor j, _ := range c.Rules.Anyfor 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が適用されるように変更されています。

この変更は、機能的な変更ではなく、コードのスタイルと保守性に関する改善です。しかし、大規模なコードベースにおいて、このような自動化された簡略化は、コードレビューの負担を軽減し、開発者がより本質的なロジックに集中できる環境を提供します。

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

このコミットにおけるコアとなるコードの変更は、主に以下のファイルに見られます。

  1. src/pkg/exp/locale/collate/Makefile:
    • tables: ターゲットにおいて、gofmt -w tables.gogofmt -w -s tables.go に変更されました。
  2. 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)} に変更。
  3. src/pkg/exp/locale/collate/build/contract_test.go:
    • 同様に、スライスリテラルの初期化において、[]stridx{...}contractTrieSet{...} の形式が {...} に簡略化されました。
  4. src/pkg/exp/locale/collate/build/order.go:
    • スライスリテラルの初期化において、[]int{...} の形式が {...} に簡略化されました。
  5. src/pkg/exp/locale/collate/maketables.go:
    • for j, _ := range c.Rules.Any のようなforループが for j := range c.Rules.Any に簡略化されました。
  6. src/pkg/exp/locale/collate/tables.go:
    • map[string]tableIndex の初期化において、tableIndex{...} の形式が {...} に簡略化されました。このファイルはロケールデータテーブルを大量に含んでいるため、この変更が最も多くの行に影響を与えています。
  7. src/pkg/exp/locale/collate/tools/colcmp/Makefile:
    • chars: ターゲットにおいて、gofmt -w chars.gogofmt -w -s chars.go に変更されました。
  8. 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言語のイディオムに沿ったコードスタイルを強制し、コードベース全体の一貫性と保守性を高めるためのものです。機能的な変更は含まれていませんが、コードの品質向上に寄与しています。

関連リンク

参考にした情報源リンク