ビジネスとIT活用に役立つブログBlog


<Goのパッケージ放浪記> ioパッケージに定義されている「Readerインターフェイス」について

この記事をシェアする:

今日は、Goのパッケージのソースを覗いてみたいと思います。
普段からさまざまなパッケージを利用しますが、その実装はどうなっているのかを把握し、よりGoらしいコードを書けるようになることが目的です。

今回はioパッケージのReaderインターフェイスまわりを読んでいきます。

今回覗いていくソースのバージョンは「go1.14.4」です。

Readerインターフェイス

まず、最初に定義されているのがReaderインターフェイスです。

実装時は以下のような挙動が求められています。

  • 引数に与えられた p に、 len(p) バイトまで読み込む(pに書き込まれる)
  • 読み込んだバイト数とエラーを返す
    • 読み込んだバイト数は、 0 <= n <= len(p) 以下になる
  • 呼び出し元は、エラーで処理を振り分けるより先に、 n > 0 なのかを判別すること
    • EOF(error型)を返す場合があるので
  •  len(p) == 0 の場合を除いて、 n を0、errをnilで返すことは推奨されない
    • EOFの場合も nil を返さずにEOF(error型)を返す
  • 実装するときに p を保持してはいけない

LimitedReaderでReaderインターフェイスの実装を確認する

下部にReaderインターフェイスを実装したLimitedReader構造体とそれを利用するLimitReader関数が定義されています。
LimitReader関数は、LimitedReader構造体のポインタを返します。

LimitReader関数の引数には、Readerインターフェイスを実装している任意のReaderと読み込むバイト数を指定します。
LimitedReader構造体のReadメソッドもReaderインターフェイスの実装になっています。

 p の大きさを変更したのちに、LimitedReader構造体が持つReaderのReadメソッドに処理を移譲しているのがわかります。

個人的に気になったのは、 p の長さを比較する部分です。
 len はintを返す仕様ですが、intは処理系によって32ビットか64ビットになります。

LimitedReaderのようなデータを扱う構造体では、明示的にint64を指定しているので、 int64に変換して長さを比較しているのだと思います。

余談ですが、積極的に処理系に依存しない型を使っていってもいいのかというと・・・。

When you need an integer value you should use int unless you have a specific reason to use a sized or unsigned integer type.

「A Tour of Go」の中で、特別な理由がない限りはintを使えと書いてあります。

そして、最後にLimitedReaderから呼び出されるReadの実装として、stringsパッケージのReader構造体のReadメソッドを見てみます。

builtinパッケージのcopy関数を呼んで、 b にコピーして読み込みを実装しています。
読み込み済みのインデックスとsの長さを比較しているので、Readの初回呼び出し以降は、 0, EOF を返すようになっています。

Readerを利用する側のコードを確認する

今度はReaderを利用している例として、bufferパッケージのReadFrom関数の実装を見てみます。

まずはこの関数が実装しているioパッケージのReaderFromインターフェイスを確認します。

  •  n で読み込んだバイト数を返す
  • errはEOFを除いてエラーを返す
    • EOFはエラーとして返さない

引数でReaderを受け取り、Readメソッドを呼び出しています。
呼び出した後は、先ほどのReaderインターフェイスに書いてあった通りに、まずmでバイト数を確認してします。
そのあとにエラーを確認して、エラーがEOFの場合は nil を、その他の場合はそのまま返すようになっています。
ReaderFromインターフェイスの仕様を意識した実装になっていることがわかります。

まとめ

今回はioパッケージのReaderインターフェイスを中心にコードを覗いてみました。
ほんの少しのコードリーディングでも学ぶものが多かったです。
どのようにインターフェイスを利用しているのか、いつint64を使うのか、EOFをどのように扱っているのかなど今後の実装の参考になりそうです。


この記事のカテゴリ:

SNSで最新の情報を
受け取ることができます!