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

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

このコミットは、Go言語の標準ライブラリであるbufioパッケージとutf8パッケージに関連する変更を含んでいます。具体的には、src/lib/bufio.gosrc/lib/utf8.goの2つのファイルが影響を受けています。

コミット

  • コミットハッシュ: c00295d1158b4851c5efad739331d219f6ee01f2
  • 作者: Russ Cox rsc@golang.org
  • コミット日時: Mon Nov 24 13:29:59 2008 -0800

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

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

元コミット内容

このコミットは、チェンジリスト19913の自動化されたG4ロールバックです。元の変更は以下の内容でした。

bufio.ReadRune

変更の背景

このコミットは、以前の変更(チェンジリスト19913)がビルドを壊したため、その変更を元に戻す(ロールバックする)ために行われました。元の変更はbufio.ReadRuneという関数の導入に関するものでしたが、これが何らかの形でGoのビルドプロセスに問題を引き起こしたため、安定性を確保するために即座にロールバックされました。

前提知識の解説

Go言語におけるbufioパッケージ

bufioパッケージは、Go言語の標準ライブラリの一部であり、バッファリングされたI/O(入出力)を提供します。これにより、ディスクやネットワークからの読み書きの効率が向上します。例えば、ファイルから1バイトずつ読み込むのではなく、ある程度のデータをまとめてバッファに読み込み、そこから処理することで、システムコール(OSへの要求)の回数を減らし、パフォーマンスを向上させることができます。bufio.Readerbufio.Writerといった型が主要なコンポーネントです。

Go言語におけるutf8パッケージとrune

Go言語では、文字列はUTF-8でエンコードされたバイトのシーケンスとして扱われます。runeはGo言語におけるUnicodeコードポイントを表す型であり、実体はint32のエイリアスです。UTF-8では、1つのUnicode文字が1バイトから4バイトの可変長で表現されます。

utf8パッケージは、UTF-8エンコードされたバイトシーケンスを操作するためのユーティリティ関数を提供します。例えば、utf8.DecodeRuneはバイトスライスから次のUTF-8エンコードされたUnicodeコードポイント(rune)とそのバイトサイズをデコードします。utf8.FullRuneは、与えられたバイトスライスが完全なUTF-8エンコードされたruneを含んでいるかどうかをチェックします。

ロールバックとは

ソフトウェア開発における「ロールバック」とは、以前に適用された変更を元に戻し、システムやコードベースを以前の安定した状態に戻すプロセスを指します。これは、新しい変更が予期せぬバグ、パフォーマンスの低下、またはビルドの失敗などの問題を引き起こした場合に、迅速に問題を解決し、システムの安定性を回復するために行われます。バージョン管理システム(Gitなど)では、特定のコミットを元に戻す機能が提供されています。このコミットでは、Google内部で使用されていたバージョン管理システム「G4」の自動化されたロールバック機能が使用されたことが示唆されています。

技術的詳細

このコミットの技術的な詳細は、主にbufio.ReadRune関数の削除と、それに伴うutf8パッケージの関連定数の削除に集約されます。

bufio.ReadRune関数の削除

元の変更で導入され、このコミットで削除されたbufio.ReadRune関数は、bufio.BufRead型(現在のbufio.Readerに相当)のメソッドとして、バッファリングされた入力ストリームから単一のUnicode文字(rune)を読み取ることを目的としていました。

削除されたコードスニペットを見ると、この関数は以下のようなロジックを持っていました。

  1. バッファの確認と補充: b.r + utf8.UTFMax > b.w && !utf8.FullRune(b.buf[b.r:b.w])という条件で、バッファに完全なruneをデコードするのに十分なバイトがあるか、またはバッファを補充する必要があるかをチェックしていました。utf8.UTFMaxはUTF-8エンコードされたruneの最大バイト長(4バイト)を示します。
  2. バッファの補充: b.Fill()を呼び出して、基になるI/Oソースからさらにデータをバッファに読み込もうとします。
  3. エラーハンドリング: b.errが設定されている場合、エラーを返します。また、バッファが補充されなかった場合(つまり、読み込むデータがもうない場合)や、バッファが空の場合にはEndOfFileエラーを返す可能性がありました。
  4. Runeのデコード: 最初のバイトがASCII範囲内(rune < 0x80)であれば1バイトとして扱い、そうでなければutf8.DecodeRuneを使用して複数バイトのruneをデコードしていました。
  5. バッファポインタの更新: 読み取ったruneのサイズ分だけ、バッファの読み取りポインタb.rを進めていました。

この関数がビルドを壊した具体的な理由はコミットメッセージからは不明ですが、初期のGo言語の設計段階において、bufioutf8の連携、特にバッファリングされたストリームからの可変長文字の効率的かつ正確な読み取りに課題があったことを示唆しています。

src/lib/utf8.goからのUTFMax定数の削除

bufio.ReadRuneの削除に伴い、src/lib/utf8.goからUTFMax定数も削除されています。

--- a/src/lib/utf8.go
+++ b/src/lib/utf8.go
@@ -7,7 +7,6 @@
 package utf8
 
 export const (
-	UTFMax = 4;
 	RuneError = 0xFFFD;
 	RuneSelf = 0x80;
 	RuneMax = 1<<21 - 1;

これは、UTFMaxbufio.ReadRune内で使用されていたため、その関数が不要になったことで、関連する定数も不要になったことを意味します。初期のGo言語では、エクスポートされる定数や関数の設計がまだ流動的であり、このような変更は珍しくありませんでした。

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

src/lib/bufio.go

--- a/src/lib/bufio.go
+++ b/src/lib/bufio.go
@@ -3,12 +3,8 @@
 // license that can be found in the LICENSE file.\n \n package bufio
-\n-import (\n-\t\"os\";\n-\t\"io\";\n-\t\"utf8\";\n-)\n+import \"os\"\n+import \"io\"\n \n \n // TODO:\n@@ -69,7 +65,7 @@ func (b *BufRead) Fill() *os.Error {\n \t}\n \n \t// Slide existing data to beginning.\n-\tif b.w > b.r {\n+\tif b.w >  b.r {\n \t\tCopySlice(b.buf[0:b.w-b.r], b.buf[b.r:b.w]);\n \t\tb.w -= b.r;\n \t} else {\n@@ -144,30 +140,6 @@ func (b *BufRead) UnreadByte() *os.Error {\n \treturn nil\n }\n \n-// Read a single Unicode character; returns the rune and its size.\n-func (b *BufRead) ReadRune() (rune int, size int, err *os.Error) {\n-\tfor b.r + utf8.UTFMax > b.w && !utf8.FullRune(b.buf[b.r:b.w]) {\n-\t\tn := b.w - b.r;\n-\t\tb.Fill();\n-\t\tif b.err != nil {\n-\t\t\treturn 0, 0, b.err\n-\t\t}\n-\t\tif b.w - b.r == n {\n-\t\t\t// no bytes read\n-\t\t\tif b.r == b.w {\n-\t\t\t\treturn 0, 0, EndOfFile\n-\t\t\t}\n-\t\t\tbreak;\n-\t\t}\n-\t}\n-\trune, size = int(b.buf[b.r]), 1;\n-\tif rune >= 0x80 {\n-\t\trune, size = utf8.DecodeRune(b.buf[b.r:b.w]);\n-\t}\n-\tb.r += size;\n-\treturn rune, size, nil\n-}\n-\n // Helper function: look for byte c in array p,\n // returning its index or -1.\n func FindByte(p *[]byte, c byte) int {\n```

- `bufio.go`から`utf8`のインポートが削除されました。
- `BufRead`構造体から`ReadRune()`メソッドが完全に削除されました。このメソッドは、バッファからUnicode文字(rune)を読み取るためのものでした。
- `Fill()`関数内の`if b.w > b.r`の条件式で、`>`の後に余分なスペースが追加されていますが、これは機能的な変更ではなく、おそらくフォーマットの変更かタイプミスです。

### `src/lib/utf8.go`

```diff
--- a/src/lib/utf8.go
+++ b/src/lib/utf8.go
@@ -7,7 +7,6 @@
 package utf8
 
 export const (
-\tUTFMax = 4;
 \tRuneError = 0xFFFD;
 \tRuneSelf = 0x80;
 \tRuneMax = 1<<21 - 1;
  • utf8.goからUTFMax定数が削除されました。この定数は、UTF-8エンコードされたruneの最大バイト長(4)を示していました。

コアとなるコードの解説

このコミットの核心は、bufio.ReadRune関数の削除です。この関数は、バッファリングされた入力ストリームからUnicode文字を効率的に読み取ることを意図していましたが、何らかの理由でビルドを壊したため、一時的に削除されました。

初期のGo言語では、bufioパッケージはバイトストリームの効率的な読み書きに焦点を当てており、文字(rune)レベルでの操作はbytesstringsパッケージ、あるいは直接utf8パッケージの関数を使って行うのが一般的でした。bufio.ReadRuneの導入は、bufioがより高レベルな文字ベースの読み取り機能を提供しようとした試みだったと考えられます。しかし、その実装が当時のGoのコンパイラや他の部分と互換性がなかったか、あるいはパフォーマンスや正確性に問題があった可能性があります。

UTFMax定数の削除は、bufio.ReadRuneが削除されたことによる直接的な結果です。UTFMaxReadRuneの実装内で使用されていたため、その関数がなくなったことで、この定数も不要と判断されました。これは、Go言語の標準ライブラリがまだ活発に開発されており、APIや内部実装が頻繁に変更されていた時期の典型的な例です。

このロールバックは、Go言語の開発チームがビルドの安定性を非常に重視していたことを示しています。問題のある変更を迅速に特定し、元に戻すことで、開発プロセス全体の健全性を維持していました。最終的に、Go言語にはbufio.Reader.ReadRune()というメソッドが導入されますが、それはこのコミットの時点から後のことになります。このロールバックは、その後のより堅牢な実装に向けた一時的な後退だったと言えるでしょう。

関連リンク

このコミットは2008年のものであり、Go言語の非常に初期の段階に当たります。当時のGoの設計に関する議論や、bufio.ReadRuneがなぜビルドを壊したのかについての具体的な情報は、公開されているアーカイブからは見つけにくい可能性があります。しかし、Go言語の公式リポジトリのコミット履歴をさらに深く掘り下げることで、関連する議論やその後のReadRuneの再導入に関する情報が見つかるかもしれません。

  • Go言語の公式GitHubリポジトリ: https://github.com/golang/go
  • Go言語の初期のメーリングリストアーカイブ: 2008年当時のGoに関する議論は、Google Groupsなどのメーリングリストアーカイブに存在する可能性があります。

参考にした情報源リンク