[インデックス 17154] ファイルの概要
このコミットは、Go言語の標準ライブラリ crypto/rand
パッケージ内の ExampleRead
関数のサンプルコードを簡素化するものです。具体的には、io.ReadFull
の特性をより適切に活用することで、不要な条件チェックを削除しています。
コミット
- コミットハッシュ:
ce00562607e0967ea8329aa4728a5bf4e1a8e666
- Author: Rob Pike r@golang.org
- Date: Mon Aug 12 12:52:23 2013 +1000
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/ce00562607e0967ea8329aa4728a5bf4e1a8e666
元コミット内容
crypto/rand: simplify example to exploit properties of ReadFull
No need for the complex condition.
Fixes #6089
R=golang-dev, mischief, adg
CC=golang-dev
https://golang.org/cl/12731043
変更の背景
この変更の背景には、io.ReadFull
関数の挙動に対するより深い理解と、それに基づくコードの簡素化があります。元のコードでは、io.ReadFull
の呼び出し後に、読み込んだバイト数 n
が期待されるバイト数 len(b)
と等しいかどうか、そしてエラー err
が発生していないかどうかを両方チェックしていました。
しかし、io.ReadFull
の設計上の特性として、この関数は「指定されたバイト数を正確に読み込む」ことを保証します。もし指定されたバイト数を読み込めなかった場合、io.ReadFull
は必ず非nil
のエラーを返します。したがって、n != len(b)
という条件は、err != nil
という条件が真である場合にのみ発生するため、冗長なチェックとなります。
この冗長性を排除し、よりGoらしい(idiomatic Go)エラーハンドリングにすることで、コードの可読性と簡潔性を向上させるのがこのコミットの目的です。また、この変更はIssue #6089を修正すると明記されています。
前提知識の解説
io.Reader
インターフェース
Go言語における io.Reader
は、データを読み込むための基本的なインターフェースです。
type Reader interface {
Read(p []byte) (n int, err error)
}
Read
メソッドは、データを p
に最大 len(p)
バイトまで読み込み、読み込んだバイト数 n
とエラー err
を返します。エラーが io.EOF
の場合、それ以上読み込むデータがないことを示します。
io.ReadFull
関数
io.ReadFull
は io
パッケージで提供されるヘルパー関数で、指定された io.Reader
から、与えられたバイトスライス buf
を完全に埋めるまでデータを読み込もうとします。
func ReadFull(r Reader, buf []byte) (n int, err error)
この関数の重要な特性は以下の通りです。
- 正確なバイト数の読み込み:
io.ReadFull
はlen(buf)
バイトを正確に読み込むことを試みます。 - エラーハンドリング:
- 成功:
len(buf)
バイトを完全に読み込めた場合、n
はlen(buf)
となり、err
はnil
となります。 io.EOF
:io.ReadFull
が呼び出された時点で、まだ1バイトも読み込んでいない状態でストリームの終端に達した場合(つまり、n
が0
の場合)、io.EOF
エラーを返します。io.ErrUnexpectedEOF
:io.ReadFull
がlen(buf)
バイトを読み込む前にストリームの終端に達した場合(つまり、n > 0
だがn < len(buf)
の場合)、io.ErrUnexpectedEOF
エラーを返します。これは、期待したよりも少ないバイト数しか読み込めなかったことを示します。- その他のエラー: 基になる
io.Reader
が他のエラーを返した場合、io.ReadFull
はそのエラーをそのまま返します。
- 成功:
この特性から、io.ReadFull
が nil
ではないエラーを返した場合、それは常に len(buf)
バイトを読み込めなかったことを意味します。逆に、エラーが nil
であれば、len(buf)
バイトが完全に読み込まれたことを意味します。
技術的詳細
元のコードでは、io.ReadFull
の戻り値 n
と err
を両方チェックしていました。
n, err := io.ReadFull(rand.Reader, b)
if n != len(b) || err != nil {
fmt.Println("error:", err)
return
}
ここで、io.ReadFull
の特性を考慮すると、以下のことが言えます。
- もし
io.ReadFull
がlen(b)
バイトを完全に読み込めた場合、n
はlen(b)
となり、err
はnil
となります。この場合、n != len(b)
はfalse
、err != nil
もfalse
となり、if
文の条件はfalse
となります。 - もし
io.ReadFull
がlen(b)
バイトを完全に読み込めなかった場合、io.ReadFull
は必ず非nil
のエラー (io.EOF
,io.ErrUnexpectedEOF
, または基になるリーダーからの他のエラー) を返します。この場合、err != nil
はtrue
となり、if
文の条件はtrue
となります。
したがって、n != len(b)
という条件は err != nil
が true
である場合にのみ意味を持つため、err != nil
のチェックだけで十分であり、n
のチェックは冗長になります。
新しいコードでは、この冗長なチェックを削除し、err
のみを確認するように変更されています。
_, err := io.ReadFull(rand.Reader, b)
if err != nil {
fmt.Println("error:", err)
return
}
これにより、コードはより簡潔になり、io.ReadFull
の意図する挙動をより明確に反映しています。また、n
の戻り値が使用されないため、_
で破棄することで、未使用変数の警告も回避できます。
コアとなるコードの変更箇所
--- a/src/pkg/crypto/rand/example_test.go
+++ b/src/pkg/crypto/rand/example_test.go
@@ -16,8 +16,8 @@ import (
func ExampleRead() {
c := 10
b := make([]byte, c)
- n, err := io.ReadFull(rand.Reader, b)
- if n != len(b) || err != nil {
+ _, err := io.ReadFull(rand.Reader, b)
+ if err != nil {
fmt.Println("error:", err)
return
}
コアとなるコードの解説
変更は src/pkg/crypto/rand/example_test.go
ファイルの ExampleRead
関数内で行われています。
-
変更前:
n, err := io.ReadFull(rand.Reader, b) if n != len(b) || err != nil { fmt.Println("error:", err) return }
ここでは
io.ReadFull
の戻り値n
(読み込んだバイト数) とerr
(エラー) の両方を受け取っています。そして、if
文でn
が期待されるバイト数len(b)
と異なるか、またはerr
がnil
でない場合にエラー処理を行っています。 -
変更後:
_, err := io.ReadFull(rand.Reader, b) if err != nil { fmt.Println("error:", err) return }
変更後では、
io.ReadFull
の戻り値のうちn
は_
(ブランク識別子) で破棄され、err
のみを受け取っています。そして、if
文ではerr
がnil
でないかどうかのチェックのみを行っています。
この変更により、io.ReadFull
の「指定されたバイト数を読み込めなかった場合は必ずエラーを返す」という保証を最大限に活用し、コードをより簡潔でGoのイディオムに沿ったものにしています。
関連リンク
- Go CL (Change-list): https://golang.org/cl/12731043
- GitHub Issue: https://github.com/golang/go/issues/6089
参考にした情報源リンク
io.ReadFull
のドキュメントと特性に関する情報:- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQG3rAsHZQ9oWd9ZGDrfNzZI5T86byjc3bXc77sfXAbagko-n3Q4-h-A4lvt1wv9_UzBhWcGSAUFU7GFmJLEJd3CkMyjP0AiNmOEwRJeZ0IkPWBnwdXHVcaMoEGmMptAfE1aqNo=
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHS-JlVkPj1yInXC8UUZDRwc7pLhF0lySzDD2z0iCm7BSiqzMZ3iJkj6MHkEkGqQGP5NeWLpPLWbMtTfagtLwyLQzpp6Bej2DLMoOutiQjwA==