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

[インデックス 18958] ファイルの概要

このコミットは、Go言語の標準ライブラリであるfmtパッケージのドキュメントファイルsrc/pkg/fmt/doc.goに対する変更です。fmtパッケージは、Goプログラムにおける書式設定されたI/O(入出力)を実装しており、PrintfPrintlnなどの関数を通じて、様々なデータ型の値を文字列として整形し出力する機能を提供します。doc.goファイルは、このパッケージの全体的な動作、書式指定動詞(verbs)、およびカスタムフォーマットの挙動に関する詳細な説明を含む、パッケージの公式ドキュメントの一部です。

コミット

fmt: document order of application of %T, %p and the special interfaces
Their priority was not documented.

Fixes #7571.

LGTM=adg
R=golang-codereviews, adg
CC=golang-codereviews
https://golang.org/cl/80360043

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/274fc7600d9397e1ddffbe55a73271e438312a87

元コミット内容

このコミットの主な目的は、fmtパッケージにおける%T(型)および%p(ポインタ)書式指定動詞と、FormatterGoStringererrorString()メソッドを持つインターフェースが適用される際の優先順位が、これまで明示的に文書化されていなかった点を改善することです。具体的には、これらの特殊なインターフェースが値のフォーマットにどのように影響し、どの順序で考慮されるのかを明確に記述することで、開発者がfmtパッケージの挙動をより正確に理解できるようにします。

変更の背景

Go言語のfmtパッケージは非常に柔軟で強力ですが、その柔軟性ゆえに、特定の状況下での挙動が不明瞭になることがありました。特に、カスタムフォーマットを可能にするFormatterインターフェースや、デバッグ出力に便利なGoStringerインターフェース、一般的な文字列変換を行うString()メソッド、そしてエラー処理のためのerrorインターフェースなど、複数のインターフェースが同時に実装されている型をfmt関数で出力しようとした場合、どのインターフェースのメソッドが優先的に呼び出されるのかが明確ではありませんでした。

この不明瞭さは、開発者が意図しない出力結果に遭遇したり、デバッグが困難になったりする原因となっていました。コミットメッセージにあるFixes #7571は、この問題がGitHubのIssue #7571で報告され、その解決のためにこのドキュメントの追加が必要とされたことを示しています。開発者からのフィードバックを受けて、fmtパッケージの挙動に関する公式な説明を補完し、より予測可能なものとすることがこの変更の背景にあります。

前提知識の解説

このコミットの変更内容を理解するためには、以下のGo言語の概念とfmtパッケージの知識が必要です。

Go言語のfmtパッケージの概要

fmtパッケージは、Go言語における基本的な書式設定I/O機能を提供します。fmt.Printfmt.Printlnfmt.Printfなどの関数を通じて、様々なデータ型を整形して標準出力、ファイル、または文字列に書き出すことができます。Printf系の関数では、C言語のprintfに似た書式指定文字列(format string)と書式指定動詞(verbs)を使用して、出力の形式を細かく制御します。

書式指定動詞(Verbs)

fmtパッケージでよく使われる書式指定動詞には以下のようなものがあります。

  • %v: 値をデフォルトの書式で出力します。構造体の場合、フィールド名と値が出力されます。
  • %#v: Goの構文で表現可能な形式で値を出力します。構造体の場合、フィールド名と値がGoの複合リテラル形式で出力されます。
  • %T: 値の型をGoの構文で出力します。
  • %p: ポインタの値を16進数で出力します。

fmt.Stringerインターフェース

fmt.Stringerインターフェースは、以下のように定義されています。

type Stringer interface {
    String() string
}

任意の型がこのインターフェースを実装し、String() stringメソッドを持つ場合、その型の値を%vなどの書式指定動詞で出力すると、String()メソッドの戻り値が使用されます。これは、カスタムな文字列表現を提供するための一般的な方法です。

errorインターフェース

errorインターフェースは、Go言語におけるエラー処理の標準的な方法です。

type error interface {
    Error() string
}

任意の型がこのインターフェースを実装し、Error() stringメソッドを持つ場合、その型の値をfmt関数で出力すると、Error()メソッドの戻り値が使用されます。これは、エラーオブジェクトの人間が読める形式の表現を提供します。

fmt.Formatterインターフェース

fmt.Formatterインターフェースは、より高度なカスタムフォーマットを可能にします。

type Formatter interface {
    Format(f fmt.State, c rune)
}

このインターフェースを実装する型は、Formatメソッド内でfmt.State(フラグ、幅、精度などの情報を含む)と書式指定動詞の文字(c)を受け取り、それに基づいて値を整形してfmt.Stateに書き込むことができます。これにより、fmtパッケージの全ての書式指定動詞に対してカスタムな挙動を定義できます。

fmt.GoStringerインターフェース

fmt.GoStringerインターフェースは、%#v書式指定動詞が使用された場合に特別な文字列表現を提供します。

type GoStringer interface {
    GoString() string
}

このインターフェースを実装する型は、GoString()メソッドの戻り値が%#vで出力されます。これは、デバッグ時などにGoの構文に沿った表現で値を出力したい場合に便利です。

技術的詳細

このコミットが明確にしようとしているのは、fmtパッケージが値を整形する際に、複数のインターフェースが実装されている場合にどのロジックが優先されるかという点です。

変更前のドキュメントでは、FormatterGoStringererrorString()メソッドの適用順序が曖昧でした。特に、%T%pという特定の書式指定動詞が使用された場合の挙動と、それ以外の一般的な書式指定動詞(例: %v, %s, %qなど)が使用された場合の挙動の違いが明確ではありませんでした。

このコミットによって、以下の優先順位が明確に文書化されました。

  1. %T%pの例外: fmtパッケージは、%T(型)と%p(ポインタ)の書式指定動詞で値を整形する際には、特殊なフォーマットの考慮事項(FormatterGoStringererrorString()メソッド)を適用しないことが明記されました。これは、これらの動詞が値の型やアドレスという、より低レベルで普遍的な情報を出力することを目的としているためです。カスタムフォーマットが適用されると、これらの動詞の意図が損なわれる可能性があります。

  2. 特殊なインターフェースの適用順序: %T%p以外の書式指定動詞(特に%v)が使用された場合、以下の順序でインターフェースが適用されます。

    • 1. Formatterインターフェース: 最も高い優先順位を持ちます。もし値がfmt.Formatterインターフェースを実装している場合、そのFormatメソッドが呼び出され、カスタムフォーマットが適用されます。これは、開発者が最も詳細な制御を望む場合に利用されます。

    • 2. GoStringerインターフェース: %v動詞に#フラグ(%#v)が指定され、かつ値がfmt.GoStringerインターフェースを実装している場合、そのGoString()メソッドが呼び出されます。これは、Goの構文に沿った表現を提供するためのものです。

    • 3. errorインターフェース: 値がerrorインターフェースを実装している場合、そのError()メソッドが呼び出され、エラーメッセージが文字列として整形されます。このルールは、文字列として有効な書式(%s, %q, %v, %x, %X)が指定された場合に適用されます。

    • 4. String()メソッド(fmt.Stringerインターフェース): 値がString() stringメソッド(fmt.Stringerインターフェース)を実装している場合、そのメソッドが呼び出され、カスタム文字列が整形されます。このルールも、文字列として有効な書式が指定された場合に適用されます。

この明確な順序付けにより、開発者はfmtパッケージの挙動をより正確に予測し、意図した通りの出力を得ることができるようになります。特に、複数のインターフェースを実装する複雑な型を扱う際に、このドキュメントは非常に役立ちます。

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

変更はsrc/pkg/fmt/doc.goファイルに対して行われました。以下に、変更の差分を示します。

--- a/src/pkg/fmt/doc.go
+++ b/src/pkg/fmt/doc.go
@@ -115,20 +115,25 @@
 		fmt.Printf("%v\n", i)
 will print 23.

-	If an operand implements interface Formatter, that interface
-	can be used for fine control of formatting. Similarly, if an
-	operand implements the GoStringer interface, that will be
-	invoked if the '%#v' verb is used to format the operand.
+	Except when printed using the the verbs %T and %p, special
+	formatting considerations apply for operands that implement
+	certain interfaces. In order of application:
+
+	1. If an operand implements the Formatter interface, it will
+	be invoked. Formatter provides fine control of formatting.
+
+	2. If the %v verb is used with the # flag (%#v) and the operand
+	implements the GoStringer interface, that will be invoked.

 	If the format (which is implicitly %v for Println etc.) is valid
-	for a string (%s %q %v %x %X), the following two rules also apply:
+	for a string (%s %q %v %x %X), the following two rules apply:

-	1. If an operand implements the error interface, the Error method
-	will be used to convert the object to a string, which will then
+	3. If an operand implements the error interface, the Error method
+	will be invoked to convert the object to a string, which will then
 	be formatted as required by the verb (if any).

-	2. If an operand implements method String() string, that method
-	will be used to convert the object to a string, which will then
+	4. If an operand implements method String() string, that method
+	will be invoked to convert the object to a string, which will then
 	be formatted as required by the verb (if any).

 	For compound operands such as slices and structs, the format

コアとなるコードの解説

この差分は、fmtパッケージのドキュメントにおける、特殊なインターフェースの適用順序に関する説明を大幅に改善しています。

  1. 変更前:

    • FormatterGoStringerに関する説明はありましたが、その優先順位や、他のインターフェースとの関係は不明瞭でした。
    • errorインターフェースとString()メソッドに関する説明は、%s %q %v %x %Xなどの文字列として有効な書式に適用されるという条件はありましたが、これら2つの間の優先順位や、Formatter/GoStringerとの関係は明記されていませんでした。
    • 特に、%T%pが特殊なインターフェースの適用を抑制するという重要な情報が欠落していました。
  2. 変更後:

    • Except when printed using the the verbs %T and %p, special formatting considerations apply for operands that implement certain interfaces. In order of application:という新しい文が追加され、%T%pが特殊なフォーマットを適用しないという重要な例外が明確にされました。これは、これらの動詞が型やポインタのアドレスという、より基本的な情報を出力することを意図しているためです。
    • 特殊なインターフェースの適用順序が、番号付きリストで明確に定義されました。
      • 1. If an operand implements the Formatter interface, it will be invoked.Formatterが最優先であることが明記されました。
      • 2. If the %v verb is used with the # flag (%#v) and the operand implements the GoStringer interface, that will be invoked.GoStringer%#vの場合に適用されることが明確にされました。
      • 3. If an operand implements the error interface, the Error method will be invoked...errorインターフェースが3番目の優先順位を持つことが明記されました。
      • 4. If an operand implements method String() string, that method will be invoked...String()メソッドが4番目の優先順位を持つことが明記されました。

これらの変更により、fmtパッケージのフォーマット挙動に関するドキュメントが大幅に改善され、開発者がより正確にその動作を理解し、予測できるようになりました。特に、複数のインターフェースを実装するカスタム型を扱う際の混乱が解消されることが期待されます。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント (fmtパッケージ): https://pkg.go.dev/fmt
  • このコミット自体の内容 (src/pkg/fmt/doc.goの変更差分)
  • Go言語のインターフェースに関する一般的な知識
  • Go言語のエラー処理に関する一般的な知識
  • Go言語の書式設定に関する一般的な知識
  • Go Issue #7571 (問題の背景理解のため)
  • Go Code Review CL 80360043 (変更の経緯と議論の理解のため)