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

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

このコミットは、Go言語の標準ライブラリであるbytesパッケージ内のBuffer型におけるWriteメソッドのコードを修正し、WriteStringメソッドのコードと一貫性を持たせることを目的としています。具体的には、copy関数の戻り値を直接Writeメソッドの戻り値として利用することで、冗長な変数宣言と代入を排除し、コードの簡潔性と可読性を向上させています。

コミット

commit 87ceb0cec73b93064be4b65da6bee265addc2027
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date:   Fri Jan 13 11:48:57 2012 -0800

    bytes: make Write and WriteString code look the same

    R=golang-dev, r
    CC=golang-dev
    https://golang.org/cl/5540056

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

https://github.com/golang/go/commit/87ceb0cec73b93064be4b65da6bee265addc2027

元コミット内容

bytes: make Write and WriteString code look the same

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5540056

変更の背景

Go言語のbytesパッケージには、可変長バイトバッファを提供するBuffer型があります。このBuffer型には、バイトスライスを書き込むためのWriteメソッドと、文字列を書き込むためのWriteStringメソッドが存在します。

コミット前のWriteメソッドの実装は、copy関数でデータをコピーした後、別途len(p)を戻り値として返していました。一方、WriteStringメソッドは、copy関数の戻り値を直接利用して書き込んだバイト数を返していました。このわずかな実装の違いは、機能的には同じ目的(書き込んだバイト数を返す)を達成しているにもかかわらず、コードの見た目とパターンに一貫性がない状態でした。

このコミットの背景には、Go言語のコードベース全体で一貫性のあるコーディングスタイルとパターンを維持しようとする意図があります。特に、類似の機能を持つメソッドは、可能な限り同様のコード構造を持つべきであるという原則に基づいています。これにより、コードの可読性が向上し、開発者が異なるメソッドの実装を理解する際の認知負荷が軽減されます。

前提知識の解説

bytes.Buffer

bytes.Bufferは、Go言語の標準ライブラリbytesパッケージで提供される型で、可変長のバイトバッファを実装しています。これは、バイトスライスを効率的に操作するための便利なツールであり、特にI/O操作や文字列操作で頻繁に利用されます。Bufferのゼロ値はすぐに使用できる空のバッファであり、明示的な初期化は不要です。

WriteメソッドとWriteStringメソッド

  • func (b *Buffer) Write(p []byte) (n int, err error): このメソッドは、バイトスライスpの内容をバッファbの末尾に追加します。nは書き込まれたバイト数(通常はlen(p))、errはエラー情報(bytes.BufferWriteメソッドは常にnilを返します)を返します。

  • func (b *Buffer) WriteString(s string) (n int, err error): このメソッドは、文字列sの内容をバッファbの末尾に追加します。nは書き込まれたバイト数(通常はlen(s))、errはエラー情報(bytes.BufferWriteStringメソッドも常にnilを返します)を返します。

copy関数

Go言語の組み込み関数であるcopyは、ソーススライスからデスティネーションスライスへ要素をコピーします。そのシグネチャはfunc copy(dst, src []Type) intです。copy関数は、実際にコピーされた要素の数を返します。これは、デスティネーションスライスまたはソーススライスの長さの小さい方になります。bytes.BufferWriteWriteStringメソッドの文脈では、copyは常にソーススライス(pまたは[]byte(s))の全てのバイトをコピーできるため、len(p)またはlen(s)と同じ値を返します。

技術的詳細

このコミットの技術的な核心は、bytes.BufferWriteメソッドにおける戻り値の処理方法の変更です。

変更前は、Writeメソッド内でcopy(b.buf[m:], p)を実行した後、len(p)を明示的にreturnしていました。

// 変更前
func (b *Buffer) Write(p []byte) (n int, err error) {
	b.lastRead = opInvalid
	m := b.grow(len(p))
	copy(b.buf[m:], p) // ここでコピーを実行
	return len(p), nil // コピーされたバイト数を別途返す
}

一方、WriteStringメソッドは、copy関数の戻り値を直接利用していました。

// WriteString (変更前も同様のロジック)
func (b *Buffer) WriteString(s string) (n int, err error) {
	b.lastRead = opInvalid
	m := b.grow(len(s))
	return copy(b.buf[m:], []byte(s)), nil // copyの戻り値を直接返す
}

copy関数は、コピーされたバイト数をint型で返します。bytes.BufferWriteメソッドでは、growによってバッファの容量が確保されているため、copy(b.buf[m:], p)は常にlen(p)バイトをコピーし、その値を返します。したがって、copyの戻り値とlen(p)は常に同じ値になります。

この事実を利用し、コミットではWriteメソッドを以下のように変更しました。

// 変更後
func (b *Buffer) Write(p []byte) (n int, err error) {
	b.lastRead = opInvalid
	m := b.grow(len(p))
	return copy(b.buf[m:], p), nil // copyの戻り値を直接返す
}

この変更により、WriteメソッドはWriteStringメソッドと全く同じパターンで書き込みバイト数を返すようになりました。これは、コードの冗長性を排除し、より簡潔でGoらしい(idiomatic Go)記述に近づけるためのリファクタリングです。機能的な変更は一切なく、パフォーマンスへの影響もありません。純粋にコードのスタイルと一貫性を改善するための変更です。

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

--- a/src/pkg/bytes/buffer.go
+++ b/src/pkg/bytes/buffer.go
@@ -97,8 +97,7 @@ func (b *Buffer) grow(n int) int {
 func (b *Buffer) Write(p []byte) (n int, err error) {
 	b.lastRead = opInvalid
 	m := b.grow(len(p))
-	copy(b.buf[m:], p)
-	return len(p), nil
+	return copy(b.buf[m:], p), nil
 }
 
 // WriteString appends the contents of s to the buffer.  The return

コアとなるコードの解説

変更はsrc/pkg/bytes/buffer.goファイルのBuffer型に属するWriteメソッド内で行われました。

  • 削除された行:

    	copy(b.buf[m:], p)
    	return len(p), nil
    

    この2行は、まずcopy関数を呼び出してバイトスライスpの内容をバッファにコピーし、その後にlen(p)nil(エラーなし)を戻り値として返していました。

  • 追加された行:

    	return copy(b.buf[m:], p), nil
    

    この1行は、copy関数の呼び出しと、その戻り値(コピーされたバイト数)およびnilエラーを直接return文で返すように変更されました。

この変更により、copy関数の戻り値がWriteメソッドのn(書き込まれたバイト数)として直接利用されるようになり、コードが1行削減され、より簡潔になりました。これは、copy関数が常に実際にコピーされたバイト数を返すという特性と、bytes.Buffer.Writeが常にlen(p)バイトをコピーできるという前提に基づいています。

関連リンク

参考にした情報源リンク