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

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

このドキュメントは、Go言語のfmtパッケージにおけるStringerインターフェースのドキュメント修正に関するコミットbb195f67938c9f32985d3b2c231f3d43c4ef83f8について詳細に解説します。

コミット

commit bb195f67938c9f32985d3b2c231f3d43c4ef83f8
Author: Rob Pike <r@golang.org>
Date:   Wed Apr 10 14:05:34 2013 -0700

    fmt: tweak the explanation of Stringer to be more correct and less specific
    The String method is called whenever the printing operation wants a string,
    not just for %s and %v.
    
    R=golang-dev, bradfitz
    CC=golang-dev
    https://golang.org/cl/8638043

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

https://github.com/golang/go/commit/bb195f67938c9f32985d3b2c231f3d43c4ef83f8

元コミット内容

fmt: tweak the explanation of Stringer to be more correct and less specific
The String method is called whenever the printing operation wants a string,
not just for %s and %v.

変更の背景

このコミットは、Go言語の標準ライブラリであるfmtパッケージ内のStringerインターフェースに関するドキュメントの記述を修正することを目的としています。従来のドキュメントでは、StringerインターフェースのString()メソッドが呼び出される条件として、%s%vといった特定のフォーマット指定子、またはPrintのような非フォーマット出力関数にオペランドとして渡された場合のみが挙げられていました。

しかし、実際のfmtパッケージの動作では、String()メソッドはより広範な状況で、つまり「出力操作が文字列を必要とする場合」であれば常に呼び出されます。このコミットは、この実際の動作とドキュメントの記述との間の乖離を解消し、より正確で、かつ特定のフォーマット指定子に限定されない一般的な説明に修正するために行われました。これにより、開発者がStringerインターフェースの挙動をより正確に理解できるようになります。

前提知識の解説

Go言語のfmtパッケージ

fmtパッケージは、Go言語の標準ライブラリの一部であり、C言語のprintfscanfに似た、フォーマットされた入出力機能を提供します。主に、コンソールやファイルへのテキスト出力、および入力の読み取りに使用されます。

fmtパッケージの主要な機能には以下のようなものがあります。

  • 出力関数:
    • fmt.Print(), fmt.Println(), fmt.Printf(): コンソールに出力します。Printf%v (デフォルトフォーマット), %s (文字列), %d (整数) などの「動詞」と呼ばれるプレースホルダーを使用してフォーマットを制御します。
    • fmt.Sprint(), fmt.Sprintln(), fmt.Sprintf(): 出力結果を文字列として返します。
    • fmt.Fprint(), fmt.Fprintln(), fmt.Fprintf(): 指定されたio.Writer(例: ファイル)にフォーマットされた出力を書き込みます。
  • 入力関数:
    • fmt.Scan(), fmt.Scanln(), fmt.Scanf(): os.Stdinから入力を読み取ります。
    • fmt.Sscan(), fmt.Sscanln(), fmt.Sscanf(): 文字列から入力を読み取ります。

Stringerインターフェース

Stringerインターフェースは、fmtパッケージで定義されている非常に基本的なインターフェースです。このインターフェースは、単一のメソッドString() stringを持ちます。

type Stringer interface {
    String() string
}

任意の型がこのString()メソッドを実装すると、その型はStringerインターフェースを満たしていると見なされます。Stringerインターフェースの主な目的は、fmtパッケージの関数(例: fmt.Println, fmt.Printf)やその他の文字列フォーマット技術で使用される際に、オブジェクトがどのように文字列として表現されるかを制御することです。

例えば、カスタム型を定義し、その型にString()メソッドを実装することで、その型のインスタンスをfmt.Printlnなどで出力した際に、開発者が意図した形式の文字列が得られるようになります。

package main

import "fmt"

type Person struct {
    Name string
    Age  int
}

// Person型がStringerインターフェースを実装
func (p Person) String() string {
    return fmt.Sprintf("%s (%d years old)", p.Name, p.Age)
}

func main() {
    p := Person{"Alice", 30}
    fmt.Println(p) // 出力: Alice (30 years old)
}

この例では、Person型がString()メソッドを実装しているため、fmt.Println(p)が呼び出された際に、Person型のデフォルトの文字列表現ではなく、String()メソッドが返す文字列が使用されます。

技術的詳細

このコミットの技術的な詳細は、src/pkg/fmt/print.goファイル内のStringerインターフェースのコメントの修正に集約されます。

変更前は、StringerインターフェースのStringメソッドが呼び出される条件について、以下のように記述されていました。

// The String method is used to print values passed as an operand
// to a %s or %v format or to an unformatted printer such as Print.

この記述は、String()メソッドが%s%vといった特定のフォーマット指定子、またはPrintのような非フォーマット出力関数に限定して呼び出されるかのような印象を与えます。

しかし、fmtパッケージの内部実装では、String()メソッドはより一般的な状況、すなわち「出力操作が文字列を必要とする場合」に呼び出されます。例えば、fmt.Errorffmt.Sprintfなど、明示的に文字列を要求しないが結果的に文字列を生成する関数でも、Stringerを実装した値が渡されればString()メソッドが利用されます。

このコミットでは、この点を明確にするために、コメントが以下のように修正されました。

// The String method is used to print values passed as an operand
// to any format that accepts a string or to an unformatted printer
// such as Print.

この修正により、「%s%vフォーマット」という具体的な記述が「文字列を受け入れる任意のフォーマット」というより一般的な表現に置き換えられました。これにより、StringerインターフェースのString()メソッドが、fmtパッケージ内の文字列を扱うあらゆる出力操作において、その型の「ネイティブな」文字列表現を提供するために利用されるという、より正確な意味合いが伝わるようになりました。

この変更は、コードの動作自体を変更するものではなく、あくまでドキュメントの正確性を向上させるためのものです。しかし、Go言語のインターフェースの設計思想とfmtパッケージの柔軟な動作を理解する上で、非常に重要な修正と言えます。

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

--- a/src/pkg/fmt/print.go
+++ b/src/pkg/fmt/print.go
@@ -47,7 +47,7 @@ type State interface {
 }
 
 // Formatter is the interface implemented by values with a custom formatter.
-// The implementation of Format may call Sprintf or Fprintf(f) etc.
+// The implementation of Format may call Sprint(f) or Fprint(f) etc.
 // to generate its output.
 type Formatter interface {
 	Format(f State, c rune)
@@ -56,7 +56,8 @@ type Formatter interface {
 // Stringer is implemented by any value that has a String method,
 // which defines the ``native\'\' format for that value.
 // The String method is used to print values passed as an operand
-// to a %s or %v format or to an unformatted printer such as Print.
+// to any format that accepts a string or to an unformatted printer
+// such as Print.
 type Stringer interface {
 	String() string
 }

コアとなるコードの解説

上記の差分は、src/pkg/fmt/print.goファイル内の2つのインターフェースのコメントに対する修正を示しています。

  1. Formatterインターフェースのコメント修正:

    • - // The implementation of Format may call Sprintf or Fprintf(f) etc.
    • + // The implementation of Format may call Sprint(f) or Fprint(f) etc. この変更は、FormatterインターフェースのFormatメソッドの実装内で、fmtパッケージの関数を呼び出す際の例を修正しています。以前はSprintfFprintfが例示されていましたが、より一般的なSprintFprintに修正されました。これは、Formatterがフォーマット指定子(verb)を伴わない一般的な文字列生成や出力を行う場合にも適用されることを示唆しています。
  2. Stringerインターフェースのコメント修正:

    • - // to a %s or %v format or to an unformatted printer such as Print.
    • + // to any format that accepts a string or to an unformatted printer
    • + // such as Print. これがこのコミットの主要な変更点です。StringerインターフェースのString()メソッドが呼び出される条件に関する説明が修正されています。
    • 変更前は、「%sまたは%vフォーマット、あるいはPrintのような非フォーマット出力関数にオペランドとして渡された場合」と限定的に記述されていました。
    • 変更後は、「文字列を受け入れる任意のフォーマット、あるいはPrintのような非フォーマット出力関数にオペランドとして渡された場合」と、より広範で正確な表現に修正されました。

この修正により、StringerインターフェースのString()メソッドが、fmtパッケージ内で文字列を必要とするあらゆる状況で利用されるという、その真の汎用性が明確に示されています。これは、fmtパッケージが内部的に型を文字列に変換する必要がある場合に、まずStringerインターフェースの実装をチェックするというGo言語の設計原則をより正確に反映しています。

関連リンク

参考にした情報源リンク