以下の内容はhttps://devlights.hatenablog.com/entry/2025/03/10/073000より取得しました。


Goメモ-549 (*bytes.Bufferをio.ReadWriteCloserに変換)

関連記事

GitHub - devlights/blog-summary: ブログ「いろいろ備忘録日記」のまとめ

概要

以下、自分用のメモです。忘れないようにここにメモメモ。。。

bytes.Buffer はとても便利な型ですね。個人的にはGoで利用している型のトップ3には余裕で入っています。

io.Readerにもなれるし、io.Writerにもなれる。でも、io.Closerを実装していないので、io.ReadWriteCloserにはなれない。

通信処理を書く際に net.Conn を使いますが、この net.Conn さんは io.ReadWriteCloser を実装しています。ついでに os.File さんも実装しています。

なので、これらを使った処理をテスト可能にする際に io.ReadWriteCloser で処理するようにすると、テスト時にモックが渡しやすい。

で、テスト時の値には bytes.Buffer を使いたい。

ラップした型を用意して、空実装のCloseメソッドを用意すれば事足りるのですが、限定的な場面で利用するだけのときは匿名構造体を使ったほうが楽です。

サンプル

main.go

package bufferop

import (
    "bytes"
    "io"
    "os"
)

// ToReadWriteCloser は、bytes.Buffer を io.ReadWriteCloser に変換するサンプルです.
//
// bytes.Bufferは、既に io.Reader と io.Writer を実装していますが
// io.Closer は実装していません。そのため、そのままでは
// os.File や net.Conn のように io.ReadWriteCloser としては利用できません。
//
// bytes.Bufferをラップし、Closeメソッドを空実装した型を別途用意すれば良いのですが面倒です。
// リミテッドな使い方(特定の関数に渡したいだけ)の場合は、匿名構造体と io.NopCloser を利用した方が楽です。
//
// # REFERENCES
//   - https://zenn.dev/nobonobo/articles/297dc5cbc554d6
func ToReadWriteCloser() error {
    // funcs
    var (
        // 変換
        c = func(b *bytes.Buffer) io.ReadWriteCloser {
            // 匿名構造体を使って、io.ReadWriteCloser の実装を用意。
            //   io.ReadWriteCloser は io.Reader, io.Writer, io.Closer の合成インターフェースとなる。
            //   なので、その3つを実装していれば良いことになる。
            return &struct {
                io.ReadCloser // io.Reader と io.Closer
                io.Writer     // io.Writer
            }{
                io.NopCloser(b), // io.ReaderはBufferが実装済み。io.Closerは空実装。
                b,               // io.WriterはBufferが実装済み。
            }
        }
        // 書き込み
        w = func(rwc io.ReadWriteCloser) {
            _, _ = rwc.Write([]byte("hello\n"))
        }
        // 読み込み
        r = func(rwc io.ReadWriteCloser) {
            io.Copy(os.Stdout, rwc)
        }
    )

    var (
        b   bytes.Buffer
        rwc = c(&b)
    )
    w(rwc)
    r(rwc)

    return nil
}

shell

実行すると以下のように出力されます。

$ task
task: [build] go build -o "/workspace/try-golang/try-golang" .
task: [run] ./try-golang -onetime

ENTER EXAMPLE NAME: bufferop_to_readwritecloser

[Name] "bufferop_to_readwritecloser"
hello


[Elapsed] 40.39µs

参考情報

try-golang/examples/basic/bufferop/to_readwritecloser.go at main · devlights/try-golang · GitHub

Goのおすすめ書籍


過去の記事については、以下のページからご参照下さい。

サンプルコードは、以下の場所で公開しています。




以上の内容はhttps://devlights.hatenablog.com/entry/2025/03/10/073000より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14