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

[インデックス 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パッケージの基本的な使い方:

  1. flag.Type("name", defaultValue, "usage string")でフラグを定義します。TypeBool, Int, Stringなどがあります。
  2. flag.Parse()を呼び出して、コマンドライン引数を解析します。
  3. 定義したフラグのポインタを介して値にアクセスします。

このコミットでは、gofmtが内部でflagパッケージを使用してインデント関連のフラグを定義・処理している部分が変更されています。

技術的詳細

このコミットの技術的な核心は、gofmtがインデントとアラインメントの挙動を制御するために使用していた内部ロジックと、それを外部に公開するコマンドラインフラグのインターフェースの簡素化にあります。

変更前の挙動

変更前は、gofmtは以下のフラグを持っていました。

  • -spaces: このフラグがtrueの場合、gofmtはタブの代わりにスペースを使用してコードをアラインメントしていました。これは主に、コード内の要素を垂直に揃える際に、タブではなくスペースを使うことを意味します。
  • -tabindent: このフラグがtrueの場合、gofmtはインデントにタブを使用しました。このフラグは-spacesとは独立して機能するとされていました。

この組み合わせは、特に「アラインメント」と「インデント」という用語の使い分けが曖昧な場合、ユーザーにとって混乱を招きました。例えば、ユーザーが「スペースを使いたい」と思ったときに-spacesを指定しても、インデント自体は-tabindentの設定に依存するため、期待通りの結果にならない可能性がありました。

変更後の挙動

このコミットでは、以下の変更が行われました。

  1. -spacesフラグの削除: アラインメントにスペースを使用するかどうかを明示的に制御する-spacesフラグが完全に削除されました。
  2. -tabindentから-tabsへの名称変更と意味の変更:
    • フラグ名が-tabindentから-tabsに変更されました。
    • -tabs=trueの場合、gofmtはインデントにタブを使用します。
    • -tabs=false(またはフラグが指定されない場合)の場合、gofmtはインデントにスペースを使用します。

この変更により、インデントの挙動は単一の-tabsフラグによって制御されるようになりました。デフォルトではスペースが使用され、明示的にタブを使用したい場合にのみ-tabs=trueを指定するという、より一般的な慣習に沿った形になりました。

内部的なprinterModeの変更

gofmtの内部では、go/printerパッケージがコードのフォーマットを担当しています。このパッケージは、フォーマットの挙動を制御するためのModeビットフラグを持っています。このコミットでは、gofmtprinter.Modeを設定するロジックも変更されました。

変更前は、printerModeの初期化はuint(0)から始まり、その後-tabindent-spacesフラグの値に基づいてprinter.TabIndentprinter.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コマンドの主要なロジックを含んでいます。

  1. フラグの定義部分の変更:

    -	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との独立性に関する記述が削除されました。これは、このフラグがインデントの唯一の制御点となったことを示唆しています。
  2. initPrinterMode関数の変更: この関数は、go/printerパッケージに渡すprinterModeを設定する役割を担っています。printerModeは、フォーマットの挙動を制御するビットフラグの集合です。

    -	printerMode = uint(0)
    +	printerMode = printer.UseSpaces
     	if *tabIndent {
     		printerMode |= printer.TabIndent
     	}
    --	if *useSpaces {
    --		printerMode |= printer.UseSpaces
    --	}
    
    • 変更前は、printerModeuint(0)で初期化されていました。これは、どのフォーマットオプションもデフォルトでは有効になっていない状態を意味します。
    • 変更後、printerModeprinter.UseSpacesで初期化されるようになりました。これは、gofmtがデフォルトでスペースを使用してアラインメント(およびインデント)を行うことを意味します。
    • if *useSpacesブロックが削除されました。これは、useSpacesフラグが廃止されたため、その値に基づいてprinter.UseSpacesビットを設定する必要がなくなったためです。
    • if *tabIndentブロックは残っていますが、ここで参照される*tabIndentは新しい-tabsフラグの値を指します。もし-tabstrueであれば、printerModeprinter.TabIndentビットが追加され、タブによるインデントが有効になります。

これらの変更により、gofmtのインデント制御は、デフォルトでスペースを使用し、-tabs=trueが指定された場合にのみタブを使用するという、よりシンプルで直感的なモデルに移行しました。

関連リンク

参考にした情報源リンク

  • 上記のGitHubコミットページおよびGo Gerritの変更リスト。
  • Go言語のflagパッケージのドキュメント: https://pkg.go.dev/flag
  • Go言語のgo/printerパッケージのドキュメント: https://pkg.go.dev/go/printer
  • gofmtに関する一般的な情報源(Goブログ、Goコミュニティの議論など)。