0Pricing
Go Academy · レッスン

カスタムReaderの実装

独自のストリームを構築します

「カスタムReaderの実装」はCoddyKit上の無料Go Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはGo Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Go Academyコースには全4レッスンが含まれています。

独自のストリームを構築する

1つのメソッドだけを持つio.Readerインターフェースを実装すれば、カスタムデータソースを作成できます。その型は、すべてのioヘルパーと組み合わせて使えるようになります。

実装するメソッド

型にRead(p []byte) (n int, err error)を実装します。pにデータを格納して件数を返し、読み取りが完了したらio.EOFを返します。

定数リーダー

ここでは、同じバイトを無限に出力し、LimitReaderで上限を設けたリーダーを扱います。

package main

import (
	"fmt"
	"io"
)

type constReader struct{ ch byte }

func (c constReader) Read(p []byte) (int, error) {
	for i := range p {
		p[i] = c.ch
	}
	return len(p), nil
}

func main() {
	r := io.LimitReader(constReader{ch: 'A'}, 5)
	data, _ := io.ReadAll(r)
	fmt.Println(string(data))
}

EOFの通知

データソースを使い切ったらio.EOFを返します。単独で返すことも、最後のバイト列と一緒に返すこともできます。

package main

import (
	"fmt"
	"io"
)

type oneShot struct{ done bool }

func (o *oneShot) Read(p []byte) (int, error) {
	if o.done {
		return 0, io.EOF
	}
	o.done = true
	n := copy(p, []byte("once"))
	return n, nil
}

func main() {
	data, _ := io.ReadAll(&oneShot{})
	fmt.Println(string(data))
}

スライスからの読み取り

カスタムリーダーは、元データ内の位置を保持し、呼び出しごとに一部のデータを返すことができます。

package main

import (
	"fmt"
	"io"
)

type sliceReader struct {
	data []byte
	pos  int
}

func (s *sliceReader) Read(p []byte) (int, error) {
	if s.pos >= len(s.data) {
		return 0, io.EOF
	}
	n := copy(p, s.data[s.pos:])
	s.pos += n
	return n, nil
}

func main() {
	r := &sliceReader{data: []byte("custom")}
	out, _ := io.ReadAll(r)
	fmt.Println(string(out))
}

変換するリーダー

別のリーダーをラップして、バイトをその場で変換します。ここでは、ストリームの各バイトを大文字に変換しています。

package main

import (
	"bytes"
	"fmt"
	"io"
)

type upper struct{ r io.Reader }

func (u upper) Read(p []byte) (int, error) {
	n, err := u.r.Read(p)
	for i := 0; i < n; i++ {
		if p[i] >= 'a' && p[i] <= 'z' {
			p[i] -= 32
		}
	}
	return n, err
}

func main() {
	out, _ := io.ReadAll(upper{r: bytes.NewReader([]byte("hello"))})
	fmt.Println(string(out))
}

バッファの長さを守る

len(p)を超えるバイトを書き込んではいけません。小さい方のスライスに合わせて範囲が制限されるcopy(p, src)を使い、コピーしたバイト数を返してください。

値レシーバーとポインタレシーバー

リーダーが位置や状態を保持する場合は、呼び出しの間も変更を維持できるようにポインタレシーバーを使います。状態を持たないリーダーでは値レシーバーを使えます。

ioヘルパーとの組み合わせ

型がio.Readerを満たしているため、io.Copy、bufio.NewReader、io.LimitReaderなどにそのまま組み込んで使えます。

package main

import (
	"io"
	"os"
)

type dots struct{ left int }

func (d *dots) Read(p []byte) (int, error) {
	if d.left == 0 {
		return 0, io.EOF
	}
	p[0] = '.'
	d.left--
	return 1, nil
}

func main() {
	io.Copy(os.Stdout, &dots{left: 4})
	os.Stdout.WriteString("\n")
}

よくある落とし穴

  • io.EOFを返し忘れる(読み取りが無限に続く)
  • len(p)を超えて書き込む
  • 状態を持つリーダーで値レシーバーを使う

カスタムリーダーを使う理由

カスタムリーダーを使うと、ジェネレーター、デコーダー、レートリミッター、暗号化ストリームなど、あらゆるソースをGoの汎用的なI/Oエコシステムに適応させられます。

クイックチェック

カスタムリーダーの知識を確認しましょう。

まとめ

独自のストリームを構築する方法を学びました。

  • Read(p []byte) (int, error)を実装します
  • copyを使い、len(p)を守ります
  • 完了したらio.EOFを返します
  • 状態を持つリーダーにはポインタレシーバーを使います
  • すべてのioヘルパーと自由に組み合わせられます

よくある質問

「カスタムReaderの実装」レッスンは無料ですか?

はい。「カスタムReaderの実装」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Go Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Go Academyコースには全4レッスンが含まれています。

「カスタムReaderの実装」で何を学びますか?

独自のストリームを構築します ブラウザで直接実行するハンズオンコードでGo Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Go Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのGo Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。

「カスタムReaderの実装」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このGo Academyレッスンでコードを書いて実行できますか?

はい。すべてのGo Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. Readerインターフェース
  2. Writerインターフェース
  3. ioユーティリティ関数
  4. カスタムReaderの実装
← Go Academyに戻る