[インデックス 10758] ファイルの概要
このコミットは、Go言語の公式フォーマッタであるgofmtコマンドのコマンドラインフラグを簡素化するものです。具体的には、インデントに関するオプションの扱いが変更され、より直感的で一貫性のある挙動が実現されました。
コミット
commit fe746335aaf2b7e31e4582439b8cbe25c92004a2
Author: Robert Griesemer <gri@golang.org>
Date: Tue Dec 13 14:03:25 2011 -0800
gofmt: simplify flags
-tabs replaces -tabindent
-spaces has been removed
R=golang-dev, adg, rsc
CC=golang-dev
https://golang.org/cl/5487066
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/fe746335aaf2b7e31e4582439b8cbe25c92004a2
元コミット内容
gofmtのフラグを簡素化する。
-tabsが-tabindentを置き換える。
-spacesは削除された。
変更の背景
gofmtはGo言語のコードを自動的にフォーマットするツールであり、Goエコシステムにおいてコードの一貫性を保つ上で非常に重要な役割を担っています。初期のgofmtには、インデントのスタイルを制御するためのいくつかのフラグが存在しました。
このコミット以前は、インデントに関する主要なフラグとして以下の2つがありました。
-spaces: タブの代わりにスペースでアラインメントを行う。-tabindent:-spacesフラグとは独立して、タブでインデントを行う。
これらのフラグは、特にアラインメントとインデントの区別が曖昧であったり、互いの関係性が直感的でなかったりするため、ユーザーにとって混乱を招く可能性がありました。例えば、-spacesが「タブの代わりにスペースでアラインメント」を意味する一方で、-tabindentが「タブでインデント」を意味するという組み合わせは、ユーザーが期待する挙動と異なる場合がありました。
このコミットの目的は、これらのインデント関連のフラグをよりシンプルで理解しやすいものに再設計することでした。具体的には、-spacesフラグを廃止し、-tabindentをより汎用的な-tabsフラグに置き換えることで、インデントの挙動を単一のフラグで制御できるようにしました。これにより、gofmtの使い勝手が向上し、ユーザーが意図するフォーマットをより簡単に指定できるようになりました。
前提知識の解説
gofmtとは
gofmtは、Go言語のソースコードを自動的にフォーマットするツールです。Go言語のツールチェインに標準で含まれており、Goコミュニティではコードのスタイルガイドとして広く採用されています。gofmtを使用することで、開発者はコードのフォーマットに関する議論に時間を費やすことなく、コードの内容そのものに集中できます。また、すべてのGoコードが同じスタイルで書かれるため、可読性が向上し、異なる開発者間でのコードの共有やレビューが容易になります。
gofmtは、抽象構文木(AST)を解析し、Goの公式スタイルガイドに厳密に従ってコードを再構築します。これにより、インデント、スペース、改行、括弧の位置などが自動的に調整されます。
インデントとアラインメント
プログラミングにおいて、インデントとアラインメントはコードの可読性を高めるための重要な要素です。
- インデント (Indentation): コードブロックの階層構造を示すために、行の先頭に挿入される空白文字(タブまたはスペース)のことです。例えば、関数本体や
if文のブロックなどは、その親のコードよりも深くインデントされます。 - アラインメント (Alignment): コード内の特定の要素(例えば、変数宣言の型やコメントなど)を垂直方向に揃えることです。これは、コードの視覚的な構造を改善し、関連する情報を一目で把握しやすくするために行われます。
gofmtは、これらの両方を自動的に処理しますが、このコミット以前は、インデントとアラインメントの制御が異なるフラグで行われており、その区別がユーザーにとって直感的ではありませんでした。
Go言語のflagパッケージ
Go言語の標準ライブラリには、コマンドライン引数を解析するためのflagパッケージが含まれています。このパッケージを使用すると、開発者は簡単にコマンドラインフラグを定義し、その値をプログラム内で利用できます。
flagパッケージの基本的な使い方:
flag.Type("name", defaultValue, "usage string")でフラグを定義します。TypeはBool,Int,Stringなどがあります。flag.Parse()を呼び出して、コマンドライン引数を解析します。- 定義したフラグのポインタを介して値にアクセスします。
このコミットでは、gofmtが内部でflagパッケージを使用してインデント関連のフラグを定義・処理している部分が変更されています。
技術的詳細
このコミットの技術的な核心は、gofmtがインデントとアラインメントの挙動を制御するために使用していた内部ロジックと、それを外部に公開するコマンドラインフラグのインターフェースの簡素化にあります。
変更前の挙動
変更前は、gofmtは以下のフラグを持っていました。
-spaces: このフラグがtrueの場合、gofmtはタブの代わりにスペースを使用してコードをアラインメントしていました。これは主に、コード内の要素を垂直に揃える際に、タブではなくスペースを使うことを意味します。-tabindent: このフラグがtrueの場合、gofmtはインデントにタブを使用しました。このフラグは-spacesとは独立して機能するとされていました。
この組み合わせは、特に「アラインメント」と「インデント」という用語の使い分けが曖昧な場合、ユーザーにとって混乱を招きました。例えば、ユーザーが「スペースを使いたい」と思ったときに-spacesを指定しても、インデント自体は-tabindentの設定に依存するため、期待通りの結果にならない可能性がありました。
変更後の挙動
このコミットでは、以下の変更が行われました。
-spacesフラグの削除: アラインメントにスペースを使用するかどうかを明示的に制御する-spacesフラグが完全に削除されました。-tabindentから-tabsへの名称変更と意味の変更:- フラグ名が
-tabindentから-tabsに変更されました。 -tabs=trueの場合、gofmtはインデントにタブを使用します。-tabs=false(またはフラグが指定されない場合)の場合、gofmtはインデントにスペースを使用します。
- フラグ名が
この変更により、インデントの挙動は単一の-tabsフラグによって制御されるようになりました。デフォルトではスペースが使用され、明示的にタブを使用したい場合にのみ-tabs=trueを指定するという、より一般的な慣習に沿った形になりました。
内部的なprinterModeの変更
gofmtの内部では、go/printerパッケージがコードのフォーマットを担当しています。このパッケージは、フォーマットの挙動を制御するためのModeビットフラグを持っています。このコミットでは、gofmtがprinter.Modeを設定するロジックも変更されました。
変更前は、printerModeの初期化はuint(0)から始まり、その後-tabindentと-spacesフラグの値に基づいてprinter.TabIndentやprinter.UseSpacesといったビットがOR演算で追加されていました。
変更後は、printerModeの初期値がprinter.UseSpacesとなりました。これは、デフォルトでスペースによるアラインメント(およびインデント)が有効になることを意味します。そして、新しい-tabsフラグ(旧-tabindent)がtrueの場合にのみ、printer.TabIndentビットが追加されます。これにより、デフォルトでスペースが使われ、必要に応じてタブに切り替えるという新しいフラグのセマンティクスが内部的に反映されています。
この変更は、gofmtのユーザーインターフェースを簡素化するだけでなく、内部的なフォーマットロジックもより明確で一貫性のあるものに再構築したことを示しています。
コアとなるコードの変更箇所
src/cmd/gofmt/doc.go
--- a/src/cmd/gofmt/doc.go
+++ b/src/cmd/gofmt/doc.go
@@ -36,10 +36,8 @@ The flags are:
Formatting control flags:
-comments=true
Print comments; if false, all comments are elided from the output.
-- -spaces
-- Align with spaces instead of tabs.
-- -tabindent
-- Indent with tabs independent of -spaces.
++ -tabs=true
++ Indent with tabs; if false, spaces are used instead.
-tabwidth=8
Tab width in spaces.
src/cmd/gofmt/gofmt.go
--- a/src/cmd/gofmt/gofmt.go
+++ b/src/cmd/gofmt/gofmt.go
@@ -34,8 +34,7 @@ var (
// layout control
comments = flag.Bool("comments", true, "print comments")
tabWidth = flag.Int("tabwidth", 8, "tab width")
- tabIndent = flag.Bool("tabindent", true, "indent with tabs independent of -spaces")
- useSpaces = flag.Bool("spaces", true, "align with spaces instead of tabs")
+ tabIndent = flag.Bool("tabs", true, "indent with tabs")
// debugging
cpuprofile = flag.String("cpuprofile", "", "write cpu profile to this file")
@@ -71,13 +70,10 @@ func initParserMode() {
}
func initPrinterMode() {
- printerMode = uint(0)
+ printerMode = printer.UseSpaces
if *tabIndent {
printerMode |= printer.TabIndent
}
-- if *useSpaces {
-- printerMode |= printer.UseSpaces
-- }
}
func isGoFile(f os.FileInfo) bool {
コアとなるコードの解説
src/cmd/gofmt/doc.goの変更
このファイルはgofmtコマンドのドキュメント、特にコマンドラインフラグの説明を記述している部分です。
-spacesと-tabindentの記述が削除されました。これは、これらのフラグが廃止されたことを反映しています。- 新たに
-tabs=trueというフラグの説明が追加されました。「Indent with tabs; if false, spaces are used instead.」(タブでインデントします。falseの場合、代わりにスペースが使用されます。)という説明は、新しい-tabsフラグがインデントの主要な制御点となり、デフォルトがスペースであることを明確に示しています。
この変更は、ユーザーがgofmt -hなどでヘルプメッセージを見たときに、新しい簡素化されたフラグの情報を得るためのものです。
src/cmd/gofmt/gofmt.goの変更
このファイルはgofmtコマンドの主要なロジックを含んでいます。
-
フラグの定義部分の変更:
- tabIndent = flag.Bool("tabindent", true, "indent with tabs independent of -spaces") - useSpaces = flag.Bool("spaces", true, "align with spaces instead of tabs") + tabIndent = flag.Bool("tabs", true, "indent with tabs")useSpacesというflag.Boolの定義が完全に削除されました。これは、-spacesフラグが廃止されたためです。tabIndentという変数名はそのままですが、flag.Boolの第一引数(フラグ名)が"tabindent"から"tabs"に変更されました。これにより、コマンドラインから-tabsとしてアクセスできるようになります。tabIndentフラグのデフォルト値はtrueのままですが、説明文が「indent with tabs」と簡潔になり、-spacesとの独立性に関する記述が削除されました。これは、このフラグがインデントの唯一の制御点となったことを示唆しています。
-
initPrinterMode関数の変更: この関数は、go/printerパッケージに渡すprinterModeを設定する役割を担っています。printerModeは、フォーマットの挙動を制御するビットフラグの集合です。- printerMode = uint(0) + printerMode = printer.UseSpaces if *tabIndent { printerMode |= printer.TabIndent } -- if *useSpaces { -- printerMode |= printer.UseSpaces -- }- 変更前は、
printerModeはuint(0)で初期化されていました。これは、どのフォーマットオプションもデフォルトでは有効になっていない状態を意味します。 - 変更後、
printerModeはprinter.UseSpacesで初期化されるようになりました。これは、gofmtがデフォルトでスペースを使用してアラインメント(およびインデント)を行うことを意味します。 if *useSpacesブロックが削除されました。これは、useSpacesフラグが廃止されたため、その値に基づいてprinter.UseSpacesビットを設定する必要がなくなったためです。if *tabIndentブロックは残っていますが、ここで参照される*tabIndentは新しい-tabsフラグの値を指します。もし-tabsがtrueであれば、printerModeにprinter.TabIndentビットが追加され、タブによるインデントが有効になります。
- 変更前は、
これらの変更により、gofmtのインデント制御は、デフォルトでスペースを使用し、-tabs=trueが指定された場合にのみタブを使用するという、よりシンプルで直感的なモデルに移行しました。
関連リンク
- Go言語の公式ドキュメント: https://go.dev/
gofmtのドキュメント(Goコマンドのドキュメントの一部として):https://go.dev/cmd/gofmt/- Goのコードレビューシステム(Gerrit)の変更リスト: https://golang.org/cl/5487066
参考にした情報源リンク
- 上記のGitHubコミットページおよびGo Gerritの変更リスト。
- Go言語の
flagパッケージのドキュメント: https://pkg.go.dev/flag - Go言語の
go/printerパッケージのドキュメント: https://pkg.go.dev/go/printer gofmtに関する一般的な情報源(Goブログ、Goコミュニティの議論など)。