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

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

このコミットは、Go言語の標準ライブラリsrc/lib/io.goにおけるFullyReader(おそらくFullRead構造体のこと)のバグ修正に関するものです。具体的には、FullRead構造体のReadメソッド内でReadn関数を呼び出す際の引数が誤っていた点を修正しています。

コミット

commit 6e70c2c74fee0f7d0758d98ed919cb025c375dcc
Author: Rob Pike <r@golang.org>
Date:   Wed Nov 12 19:04:56 2008 -0800

    fix bug in FullyReader
    
    R=rsc
    DELTA=1  (0 added, 0 deleted, 1 changed)
    OCL=19131
    CL=19131

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

https://github.com/golang/go/commit/6e70c2c74fee0f7d0758d98ed919cb025c375dcc

元コミット内容

commit 6e70c2c74fee0f7d0758d98ed919cb025c375dcc
Author: Rob Pike <r@golang.org>
Date:   Wed Nov 12 19:04:56 2008 -0800

    fix bug in FullyReader
    
    R=rsc
    DELTA=1  (0 added, 0 deleted, 1 changed)
    OCL=19131
    CL=19131
---
 src/lib/io.go | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n
diff --git a/src/lib/io.go b/src/lib/io.go
index 44d072caa9..80f753a4bf 100644
--- a/src/lib/io.go
+++ b/src/lib/io.go
@@ -65,7 +65,7 @@ type FullRead struct {
 }

 func (fd *FullRead) Read(p *[]byte) (n int, err *os.Error) {
-	n, err = Readn(fd, p);
+	n, err = Readn(fd.fd, p);
 	return n, err
 }

変更の背景

このコミットは、Go言語の初期段階における標準ライブラリのバグ修正の一環として行われました。ioパッケージは、Go言語におけるI/O操作の基本的なインターフェースと実装を提供します。FullRead構造体は、おそらく特定のI/O操作をラップし、完全な読み込みを保証するためのものであったと推測されます。

このバグは、FullRead構造体のReadメソッド内で、内部的に使用されるReadn関数への引数が誤っていたために発生しました。Readn関数は、指定されたリーダーから指定されたバイト数(またはバッファの容量)を読み込むことを意図しています。しかし、元のコードではFullRead構造体自体(fd)をReadnに渡していましたが、Readnが期待するのは、実際に読み込みを行う基盤となるリーダー(fd.fd)でした。この誤った引数により、Readnが正しく動作せず、結果としてFullReadの機能が損なわれていたと考えられます。

このような初期のバグ修正は、言語やライブラリが成熟していく過程で頻繁に見られるものであり、堅牢性と正確性を確保するために不可欠です。

前提知識の解説

  • Go言語のI/Oインターフェース: Go言語では、I/O操作はio.Readerio.Writerといったインターフェースによって抽象化されています。これにより、様々な種類のデータソース(ファイル、ネットワーク接続、メモリバッファなど)に対して統一的な方法でI/O操作を行うことができます。
  • Readメソッド: io.Readerインターフェースの主要なメソッドであり、Read(p []byte) (n int, err error)というシグネチャを持ちます。これは、データをpというバイトスライスに読み込み、読み込んだバイト数nと発生したエラーerrを返します。
  • 構造体とフィールド: Go言語の構造体は、異なる型のフィールドをまとめるためのユーザー定義型です。このコミットではFullReadという構造体が登場し、その内部にfdというフィールドがあることが示唆されています。このfdフィールドが、実際のI/O操作を行う基盤となるリーダー(ファイルディスクリプタや別のio.Reader実装など)を保持していると推測されます。
  • メソッドレシーバ: Go言語のメソッドは、特定の型に関連付けられた関数です。func (fd *FullRead) Read(...)のように、関数名の前に括弧で囲まれた引数(レシーバ)を持つことで、その型のインスタンスに対して呼び出すことができます。この場合、fdFullRead構造体のポインタレシーバであり、メソッド内でFullReadインスタンスのフィールドにアクセスするために使用されます。

技術的詳細

このコミットの技術的な核心は、Go言語におけるインターフェースと構造体の利用、そしてそれらのメソッド呼び出しにおけるレシーバの扱いにあります。

FullRead構造体は、おそらく内部に別のio.Readerインターフェースを実装したオブジェクト(このコミットの差分からfd.fdと推測される)を保持しています。FullRead自身のReadメソッドは、この内部のリーダーオブジェクトを使って実際の読み込みを行うように設計されています。

元のコードでは、Readn(fd, p)と記述されていました。ここでfd*FullRead型のレシーバ変数です。つまり、Readn関数にFullRead構造体自体を渡そうとしていました。しかし、Readn関数が期待するのは、おそらくio.Readerインターフェースを満たす具体的なリーダーオブジェクトでした。

修正後のコードでは、Readn(fd.fd, p)となっています。これは、FullRead構造体の内部フィールドであるfd.fdReadn関数に渡しています。このfd.fdが、実際にバイトを読み込むための基盤となるリーダーオブジェクトであるため、Readn関数は正しく動作するようになります。

この修正は、Go言語のインターフェースの概念と、構造体のフィールドを通じて内部のオブジェクトにアクセスするという基本的なプログラミングパターンを理解していることを示しています。バグは、レシーバ変数自体を渡すべきではない場所で渡してしまったという、比較的単純な引数の誤りでした。

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

変更はsrc/lib/io.goファイル内のFullRead構造体のReadメソッドにあります。

--- a/src/lib/io.go
+++ b/src/lib/io.go
@@ -65,7 +65,7 @@ type FullRead struct {
 }

 func (fd *FullRead) Read(p *[]byte) (n int, err *os.Error) {
-	n, err = Readn(fd, p);
+	n, err = Readn(fd.fd, p);
 	return n, err
 }

コアとなるコードの解説

  • type FullRead struct { ... }: FullReadという名前の構造体の定義です。この構造体は、おそらく完全な読み込みを保証するためのロジックをカプセル化しています。差分からは見えませんが、この構造体にはfdというフィールドが存在すると推測されます。
  • func (fd *FullRead) Read(p *[]byte) (n int, err *os.Error): FullRead構造体に対するReadメソッドの定義です。
    • fd *FullRead: これはメソッドレシーバです。Readメソッドが呼び出されたFullReadインスタンスへのポインタをfdという変数名で参照できます。
    • p *[]byte: 読み込んだデータを格納するためのバイトスライスへのポインタです。
    • (n int, err *os.Error): 読み込んだバイト数とエラーを返すことを示しています。
  • - n, err = Readn(fd, p);: 変更前の行です。ここでReadn関数にFullRead構造体自体(レシーバ変数fd)を渡していました。これは誤りでした。
  • + n, err = Readn(fd.fd, p);: 変更後の行です。Readn関数にFullRead構造体の内部フィールドであるfd.fdを渡しています。このfd.fdが、実際に読み込みを行う基盤となるio.Readerインターフェースを実装したオブジェクトであるため、Readnは正しく動作します。

この修正により、FullReadReadメソッドは、その内部に持つ実際のリーダーオブジェクトからデータを読み込むようになり、FullyReaderの機能が正しく動作するようになりました。

関連リンク

参考にした情報源リンク