io.Reader と io.Writer
CoddyのGOジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 73/107。
Goの標準ライブラリは、2つの基本的なinterfacesである io.Reader と io.Writer を通じて、インターフェースベースの設計を示しています。これらのシンプルなinterfacesは、ファイル操作からネットワーク通信まで、あらゆる機能を支えています。
io.Readerインターフェースに必要なメソッドは1つだけです。
type Reader interface {
Read(p []byte) (n int, err error)
}スライスに最大で len(p) バイトを読み込み、読み込んだバイト数を返します。同様に、io.Writer は次のように定義されています。
type Writer interface {
Write(p []byte) (n int, err error)
}これらのメソッドを implementing する任意の型は、I/O エコシステム全体で動作します。
ここでは、io.Readerを実装するカスタム型を示します。
type RepeatReader struct {
Char byte
Count int
pos int
}
func (r *RepeatReader) Read(p []byte) (int, error) {
if r.pos >= r.Count {
return 0, io.EOF
}
n := 0
for n < len(p) && r.pos < r.Count {
p[n] = r.Char
n++
r.pos++
}
return n, nil
}このカスタムリーダーは、io.Reader を受け取るあらゆる関数で動作します。
reader := &RepeatReader{Char: 'A', Count: 5}
data, _ := io.ReadAll(reader)
fmt.Println(string(data)) // AAAAAこの設計により、io.Reader または io.Writer を受け取る関数を記述でき、ファイル、ネットワーク接続、バッファ、または任意のカスタム実装で動作させることができます。
チャレンジ
簡単io.Reader と io.Writer の interfaces を実装するカスタムテキストストリームプロセッサを作成しましょう!テキストがその中を流れる際に変換できる型を作成し、これらの基本的な interfaces によって powerful な I/O 合成がどのように可能になるかを示します。
コードは2つのファイルに分けて整理します。
streams.go:カスタム reader と writer の型を定義します。文字列をラップし、読み取られた
bytes数を追跡するCountingReader構造体を作成します。source 文字列用のフィールドと position tracker を持つ必要があります。指定されたスライスに source からbytesを読み込み、position を更新し、source をすべて読み終えたらio.EOFを返すRead(p []byte) (int, error)メソッドを実装します。書き込まれた data を収集し、大文字に変換する
UppercaseWriter構造体を作成します。accumulated result を内部に保存する必要があります。incomingbytesを大文字に変換して保存するWrite(p []byte) (int, error)メソッドを実装します。accumulated uppercase text を取得するためのResult() stringメソッドを追加します。型を適切に初期化するために、コンストラクター関数
NewCountingReader(source string) *CountingReaderとNewUppercaseWriter() *UppercaseWriterを作成します。main.go:標準ライブラリと連携するカスタム I/O 型の動作を示します。文字列 input を読み込み、次に
io.ReadAllとCountingReaderを使用してすべての data を読み取ります。その data をWriteメソッドでUppercaseWriterに渡します。結果を次の形式で出力します。
Original: [input] Uppercase: [result from writer] Bytes read: [total bytes]
次の input が提供されます。
- 1行のテキスト
たとえば、次の値が与えられた場合:
Hello World出力は次のようになります。
Original: Hello World
Uppercase: HELLO WORLD
Bytes read: 11また、次の値が与えられた場合:
Go interfaces are powerful出力は次のようになります。
Original: Go interfaces are powerful
Uppercase: GO INTERFACES ARE POWERFUL
Bytes read: 26重要なポイントは、CountingReader が io.Reader を実装しているため、io.ReadAll とシームレスに連携できることです。io.Reader を受け取る Go エコシステム内の任意の関数が、カスタム型である CountingReader と連携して動作します。これが interface ベースの設計の力です。
自分で試してみよう
package main
import (
"bufio"
"fmt"
"io"
"os"
)
func main() {
// 入力を読み取る
reader := bufio.NewReader(os.Stdin)
input, _ := reader.ReadString('\n')
// 末尾の改行があれば削除する
if len(input) > 0 && input[len(input)-1] == '\n' {
input = input[:len(input)-1]
}
// TODO: 入力文字列で CountingReader を作成する
// countingReader := NewCountingReader(input)
// TODO: io.ReadAll を使って CountingReader からすべてのデータを読み取る
// data, err := io.ReadAll(countingReader)
// TODO: UppercaseWriter を作成する
// upperWriter := NewUppercaseWriter()
// TODO: データを UppercaseWriter に書き込む
// upperWriter.Write(data)
// TODO: 指定された形式で結果を出力する:
// Original: [input]
// Uppercase: [ライターからの結果]
// Bytes read: [合計バイト数]
// 未使用のインポートエラーを避けるためのプレースホルダー - 実装時に削除する
_ = io.EOF
fmt.Println("Original:", input)
// fmt.Println("Uppercase:", upperWriter.Result())
// fmt.Println("Bytes read:", countingReader.Position)
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
1Go オブジェクト指向の基礎
外部ファイルGo ワークスペースとモジュールパッケージとインポート公開された名前と非公開の名前Go におけるオブジェクト指向入門クラスとしての構造体構造体へのメソッド定義ポインタレシーバと値レシーバ構造体の初期化コンストラクタ関数まとめ:簡易計算機8エラー処理とOOP
error インターフェースカスタムエラー型エラーラッピング (fmt.Errorf)センチネルエラーerrors.Is() と errors.As()Panic、Defer、Recover復習 - ファイルパーサー11標準ライブラリとOOP
io.Reader と io.Writersort.Interfacefmt.Stringer インターフェースencoding/json と構造体http.Handler インターフェースまとめ:REST API モデル自分で練習してみよう: Goオンラインコンパイラ