[インデックス 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コミュニティの議論など)。