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

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

このコミットは、Go言語の標準ライブラリであるfmtパッケージにおいて、文字列やバイトスライスを16進数でフォーマットする際に、各バイトの間にスペースを挿入する新しいフォーマット動詞 % x を追加するものです。これにより、16進数表現の可読性が向上します。

コミット

  • コミットハッシュ: afff0ff1b8442e9032266c392773a633604ff18c
  • 作者: Russ Cox rsc@golang.org
  • コミット日時: 2008年11月25日 火曜日 09:23:13 -0800
  • 変更ファイル:
    • src/lib/fmt/fmt_test.go (テストファイル)
    • src/lib/fmt/format.go (フォーマットロジックの実装ファイル)

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

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

元コミット内容

% x inserts spaces between hex bytes in string/*[]byte

R=r
DELTA=7  (7 added, 0 deleted, 0 changed)
OCL=19967
CL=19978

変更の背景

Go言語の初期段階において、fmtパッケージは基本的なフォーマット機能を提供していました。文字列やバイトスライスを16進数で出力する際には、%x動詞が使用されていましたが、これは連続した16進数文字列を生成するのみでした(例: "abc" -> "616263")。

しかし、特にバイナリデータやハッシュ値などをデバッグ目的で表示する場合、各バイトの16進数表現の間にスペースが入ることで、視覚的に区切りが明確になり、可読性が大幅に向上します(例: "abc" -> "61 62 63")。このコミットは、このようなユースケースに対応し、より人間が読みやすい形式で16進数表現を提供するために、新しいフォーマットオプション % x を導入することを目的としています。

前提知識の解説

Go言語の fmt パッケージ

fmtパッケージは、Go言語におけるフォーマットI/Oを実装するためのパッケージです。C言語のprintfscanfに似た機能を提供し、様々なデータ型を整形して文字列に出力したり、文字列からデータを読み取ったりすることができます。

主な関数には以下のようなものがあります。

  • fmt.Printf: フォーマットされた文字列を標準出力に出力します。
  • fmt.Sprintf: フォーマットされた文字列を返します。
  • fmt.Fprint: 指定されたio.Writerにフォーマットされた文字列を書き込みます。

フォーマット動詞

fmtパッケージでは、フォーマット文字列内で%に続く文字(フォーマット動詞)を使って、値の表示形式を指定します。

  • %s: 文字列をそのまま表示します。
  • %x: 整数、文字列、またはバイトスライスを小文字の16進数で表示します。
  • %X: 整数、文字列、またはバイトスライスを大文字の16進数で表示します。
  • %q: 文字列をGoの文字列リテラル形式(ダブルクォートで囲み、特殊文字をエスケープ)で表示します。

string[]byte

Go言語において、string型は不変のバイトスライスとして扱われます。[]byte型は可変のバイトスライスです。fmtパッケージの%x動詞は、これらの型に対してバイトごとの16進数表現を生成します。

ldigits (low digits)

コミットのコードスニペットに登場する ldigits は、おそらく16進数の各桁(0-9, a-f)に対応する文字を格納した配列またはスライスであると推測されます。例えば、ldigits[0]は'0'、ldigits[10]は'a'といった具合です。バイトを16進数に変換する際には、バイトを4ビットずつに分割し、それぞれの4ビット値をldigitsのインデックスとして使用して対応する16進数文字を取得します。

  • v >> 4: バイトvの上位4ビットを取得します。
  • v & 0xF: バイトvの下位4ビットを取得します。

技術的詳細

この変更は、fmtパッケージの内部実装、特に文字列やバイトスライスを16進数にフォーマットするロジックに手を入れています。

src/lib/fmt/format.go内のsx関数(おそらく "string hex" の略)が、文字列を16進数に変換する主要な役割を担っています。この関数は、入力文字列の各バイトをループ処理し、それぞれのバイトを2桁の16進数に変換して結果の文字列に連結します。

今回の変更では、このsx関数に条件付きでスペースを挿入するロジックが追加されました。具体的には、以下の条件が満たされた場合にスペースが追加されます。

  1. i > 0: 現在処理しているバイトが最初のバイトではないこと。これにより、結果文字列の先頭に余分なスペースが挿入されるのを防ぎます。
  2. f.space: フォーマッタの内部状態を示すフラグspaceが真であること。このf.spaceフラグは、フォーマット動詞が % x のようにスペースを含む場合に設定されると推測されます。fmtパッケージの内部では、フォーマット文字列を解析する際に、%と動詞の間にスペースがあるかどうかを検出し、このフラグを適切に設定するメカニズムが存在します。

このロジックにより、各バイトの16進数表現が生成された後、次のバイトの16進数表現の前にスペースが挿入されるようになります。

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

src/lib/fmt/fmt_test.go

--- a/src/lib/fmt/fmt_test.go
+++ b/src/lib/fmt/fmt_test.go
@@ -45,6 +45,7 @@ var fmttests = []FmtTest{
 	// basic bytes
 	FmtTest{ "%s",	Bytes("abc"),	"abc" },
 	FmtTest{ "%x",	Bytes("abc"),	"616263" },
+	FmtTest{ "% x",	Bytes("abc"),	"61 62 63" },
 	FmtTest{ "%x",	Bytes("xyz"),	"78797a" },
 	FmtTest{ "%X",	Bytes("xyz"),	"78797A" },
 	FmtTest{ "%q",	Bytes("abc"),	`"abc"` },

src/lib/fmt/format.go

--- a/src/lib/fmt/format.go
+++ b/src/lib/fmt/format.go
@@ -374,6 +374,9 @@ func (f *Fmt) s(s string) *Fmt {
 func (f *Fmt) sx(s string) *Fmt {
 	t := "";
 	for i := 0; i < len(s); i++ {
+\t\tif i > 0 && f.space {
+\t\t\tt += " ";
+\t\t}\n
 		v := s[i];
 		t += string(ldigits[v>>4]);
 		t += string(ldigits[v&0xF]);

コアとなるコードの解説

src/lib/fmt/fmt_test.go の変更

この変更は、新しいフォーマット動詞 % x の動作を検証するためのテストケースを追加しています。 FmtTest{ "% x", Bytes("abc"), "61 62 63" }

  • 最初の引数 "% x" は、テスト対象のフォーマット文字列です。
  • Bytes("abc") は、フォーマットされる入力データ(バイトスライスに変換された文字列 "abc")です。
  • "61 62 63" は、期待される出力結果です。これは、"abc" の各バイト('a' -> 0x61, 'b' -> 0x62, 'c' -> 0x63)が16進数に変換され、間にスペースが挿入された形式であることを示しています。

このテストケースの追加により、% x が正しく機能することが保証されます。

src/lib/fmt/format.go の変更

func (f *Fmt) sx(s string) *Fmt { ... } 関数は、文字列 s を16進数表現に変換するロジックを含んでいます。

	t := ""; // 結果を構築するための文字列変数
	for i := 0; i < len(s); i++ { // 入力文字列の各バイトをループ
		if i > 0 && f.space { // ここが追加されたロジック
			t += " "; // 最初のバイトでなく、かつ f.space フラグが真の場合にスペースを追加
		}
		v := s[i]; // 現在のバイトを取得
		t += string(ldigits[v>>4]); // バイトの上位4ビットを16進数文字に変換して追加
		t += string(ldigits[v&0xF]); // バイトの下位4ビットを16進数文字に変換して追加
	}
  • t := "";: 変換後の16進数文字列を構築するための空の文字列tを初期化します。
  • for i := 0; i < len(s); i++ { ... }: 入力文字列sの各バイトをi番目のインデックスでループ処理します。
  • if i > 0 && f.space { t += " "; }:
    • i > 0: これは、現在処理しているバイトが文字列の最初のバイトではないことを確認します。最初のバイトの前にはスペースは不要なためです。
    • f.space: これは、fmtパッケージの内部で管理されているフラグで、フォーマット動詞にスペースが含まれている(例: % x)場合にtrueになります。
    • この両方の条件が満たされた場合、tにスペースが追加されます。これにより、各バイトの16進数表現の間にスペースが挿入されます。
  • v := s[i];: 現在のループで処理するバイトをvに格納します。
  • t += string(ldigits[v>>4]);: バイトvの上位4ビットを抽出し(v>>4)、それをldigits配列のインデックスとして使用して対応する16進数文字を取得し、tに追加します。
  • t += string(ldigits[v&0xF]);: バイトvの下位4ビットを抽出し(v&0xF)、同様にldigits配列から対応する16進数文字を取得し、tに追加します。

この変更により、sx関数は % x フォーマット動詞が指定された場合に、各バイトの16進数表現の間にスペースを自動的に挿入するようになります。

関連リンク

  • Go言語 fmt パッケージのドキュメント (現在のバージョン): https://pkg.go.dev/fmt
    • %x 動詞に関する説明も参照できます。

参考にした情報源リンク

  • Go言語の公式ドキュメント (fmtパッケージ)
  • Gitのコミットログと差分情報
  • Go言語のソースコード (特に src/lib/fmt/ ディレクトリ)

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

このコミットは、Go言語の標準ライブラリであるfmtパッケージにおいて、文字列やバイトスライスを16進数でフォーマットする際に、各バイトの間にスペースを挿入する新しいフォーマット動詞 % x を追加するものです。これにより、16進数表現の可読性が向上します。

コミット

  • コミットハッシュ: afff0ff1b8442e9032266c392773a633604ff18c
  • 作者: Russ Cox rsc@golang.org
  • コミット日時: 2008年11月25日 火曜日 09:23:13 -0800
  • 変更ファイル:
    • src/lib/fmt/fmt_test.go (テストファイル)
    • src/lib/fmt/format.go (フォーマットロジックの実装ファイル)

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

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

元コミット内容

% x inserts spaces between hex bytes in string/*[]byte

R=r
DELTA=7  (7 added, 0 deleted, 0 changed)
OCL=19967
CL=19978

変更の背景

Go言語の初期段階において、fmtパッケージは基本的なフォーマット機能を提供していました。文字列やバイトスライスを16進数で出力する際には、%x動詞が使用されていましたが、これは連続した16進数文字列を生成するのみでした(例: "abc" -> "616263")。

しかし、特にバイナリデータやハッシュ値などをデバッグ目的で表示する場合、各バイトの16進数表現の間にスペースが入ることで、視覚的に区切りが明確になり、可読性が大幅に向上します(例: "abc" -> "61 62 63")。このコミットは、このようなユースケースに対応し、より人間が読みやすい形式で16進数表現を提供するために、新しいフォーマットオプション % x を導入することを目的としています。

前提知識の解説

Go言語の fmt パッケージ

fmtパッケージは、Go言語におけるフォーマットI/Oを実装するためのパッケージです。C言語のprintfscanfに似た機能を提供し、様々なデータ型を整形して文字列に出力したり、文字列からデータを読み取ったりすることができます。

主な関数には以下のようなものがあります。

  • fmt.Printf: フォーマットされた文字列を標準出力に出力します。
  • fmt.Sprintf: フォーマットされた文字列を返します。
  • fmt.Fprint: 指定されたio.Writerにフォーマットされた文字列を書き込みます。

フォーマット動詞

fmtパッケージでは、フォーマット文字列内で%に続く文字(フォーマット動詞)を使って、値の表示形式を指定します。

  • %s: 文字列をそのまま表示します。
  • %x: 整数、文字列、またはバイトスライスを小文字の16進数で表示します。
  • %X: 整数、文字列、またはバイトスライスを大文字の16進数で表示します。
  • %q: 文字列をGoの文字列リテラル形式(ダブルクォートで囲み、特殊文字をエスケープ)で表示します。
  • % v: 値をデフォルトのフォーマットで表示します。
  • %#v: Goの構文表現で値を表示します。
  • %T: 値の型を表示します。
  • %d: 10進数で整数を表示します。
  • %f: 浮動小数点数を小数点形式で表示します。

string[]byte

Go言語において、string型は不変のバイトスライスとして扱われます。[]byte型は可変のバイトスライスです。fmtパッケージの%x動詞は、これらの型に対してバイトごとの16進数表現を生成します。

ldigits (low digits)

コミットのコードスニペットに登場する ldigits は、おそらく16進数の各桁(0-9, a-f)に対応する文字を格納した配列またはスライスであると推測されます。例えば、ldigits[0]は'0'、ldigits[10]は'a'といった具合です。バイトを16進数に変換する際には、バイトを4ビットずつに分割し、それぞれの4ビット値をldigitsのインデックスとして使用して対応する16進数文字を取得します。

  • v >> 4: バイトvの上位4ビットを取得します。
  • v & 0xF: バイトvの下位4ビットを取得します。

技術的詳細

この変更は、fmtパッケージの内部実装、特に文字列やバイトスライスを16進数にフォーマットするロジックに手を入れています。

src/lib/fmt/format.go内のsx関数(おそらく "string hex" の略)が、文字列を16進数に変換する主要な役割を担っています。この関数は、入力文字列の各バイトをループ処理し、それぞれのバイトを2桁の16進数に変換して結果の文字列に連結します。

今回の変更では、このsx関数に条件付きでスペースを挿入するロジックが追加されました。具体的には、以下の条件が満たされた場合にスペースが追加されます。

  1. i > 0: 現在処理しているバイトが最初のバイトではないこと。これにより、結果文字列の先頭に余分なスペースが挿入されるのを防ぎます。
  2. f.space: フォーマッタの内部状態を示すフラグspaceが真であること。このf.spaceフラグは、フォーマット動詞が % x のようにスペースを含む場合に設定されると推測されます。fmtパッケージの内部では、フォーマット文字列を解析する際に、%と動詞の間にスペースがあるかどうかを検出し、このフラグを適切に設定するメカニズムが存在します。

このロジックにより、各バイトの16進数表現が生成された後、次のバイトの16進数表現の前にスペースが挿入されるようになります。

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

src/lib/fmt/fmt_test.go

--- a/src/lib/fmt/fmt_test.go
+++ b/src/lib/fmt/fmt_test.go
@@ -45,6 +45,7 @@ var fmttests = []FmtTest{
 	// basic bytes
 	FmtTest{ "%s",	Bytes("abc"),	"abc" },
 	FmtTest{ "%x",	Bytes("abc"),	"616263" },
+	FmtTest{ "% x",	Bytes("abc"),	"61 62 63" },
 	FmtTest{ "%x",	Bytes("xyz"),	"78797a" },
 	FmtTest{ "%X",	Bytes("xyz"),	"78797A" },
 	FmtTest{ "%q",	Bytes("abc"),	`"abc"` },

src/lib/fmt/format.go

--- a/src/lib/fmt/format.go
+++ b/src/lib/fmt/format.go
@@ -374,6 +374,9 @@ func (f *Fmt) s(s string) *Fmt {
 func (f *Fmt) sx(s string) *Fmt {
 	t := "";
 	for i := 0; i < len(s); i++ {
+\t\tif i > 0 && f.space {
+\t\t\tt += " ";
+\t\t}\n
 		v := s[i];
 		t += string(ldigits[v>>4]);
 		t += string(ldigits[v&0xF]);

コアとなるコードの解説

src/lib/fmt/fmt_test.go の変更

この変更は、新しいフォーマット動詞 % x の動作を検証するためのテストケースを追加しています。 FmtTest{ "% x", Bytes("abc"), "61 62 63" }

  • 最初の引数 "% x" は、テスト対象のフォーマット文字列です。
  • Bytes("abc") は、フォーマットされる入力データ(バイトスライスに変換された文字列 "abc")です。
  • "61 62 63" は、期待される出力結果です。これは、"abc" の各バイト('a' -> 0x61, 'b' -> 0x62, 'c' -> 0x63)が16進数に変換され、間にスペースが挿入された形式であることを示しています。

このテストケースの追加により、% x が正しく機能することが保証されます。

src/lib/fmt/format.go の変更

func (f *Fmt) sx(s string) *Fmt { ... } 関数は、文字列 s を16進数表現に変換するロジックを含んでいます。

	t := ""; // 結果を構築するための文字列変数
	for i := 0; i < len(s); i++ { // 入力文字列の各バイトをループ
		if i > 0 && f.space { // ここが追加されたロジック
			t += " "; // 最初のバイトでなく、かつ f.space フラグが真の場合にスペースを追加
		}
		v := s[i]; // 現在のバイトを取得
		t += string(ldigits[v>>4]); // バイトの上位4ビットを16進数文字に変換して追加
		t += string(ldigits[v&0xF]); // バイトの下位4ビットを16進数文字に変換して追加
	}
  • t := "";: 変換後の16進数文字列を構築するための空の文字列tを初期化します。
  • for i := 0; i < len(s); i++ { ... }: 入力文字列sの各バイトをi番目のインデックスでループ処理します。
  • if i > 0 && f.space { t += " "; }:
    • i > 0: これは、現在処理しているバイトが文字列の最初のバイトではないことを確認します。最初のバイトの前にはスペースは不要なためです。
    • f.space: これは、fmtパッケージの内部で管理されているフラグで、フォーマット動詞にスペースが含まれている(例: % x)場合にtrueになります。
    • この両方の条件が満たされた場合、tにスペースが追加されます。これにより、各バイトの16進数表現の間にスペースが挿入されます。
  • v := s[i];: 現在のループで処理するバイトをvに格納します。
  • t += string(ldigits[v>>4]);: バイトvの上位4ビットを抽出し(v>>4)、それをldigits配列のインデックスとして使用して対応する16進数文字を取得し、tに追加します。
  • t += string(ldigits[v&0xF]);: バイトvの下位4ビットを抽出し(v&0xF)、同様にldigits配列から対応する16進数文字を取得し、tに追加します。

この変更により、sx関数は % x フォーマット動詞が指定された場合に、各バイトの16進数表現の間にスペースを自動的に挿入するようになります。

関連リンク

  • Go言語 fmt パッケージのドキュメント (現在のバージョン): https://pkg.go.dev/fmt
    • %x 動詞に関する説明も参照できます。

参考にした情報源リンク

  • Go言語の公式ドキュメント (fmtパッケージ)
  • Gitのコミットログと差分情報
  • Go言語のソースコード (特に src/lib/fmt/ ディレクトリ)
  • Web検索結果: "Go fmt package % x"