web-dev-qa-db-ja.com

タイプio.Readerとして(タイプ[]バイト)を使用できません

エラーがわかりません。これは、マシン「A」で実行するmain.goです。

package main

import (
    "fmt"
    "net"
    "os"
    "github.com/mistifyio/go-zfs"
)

func main() {
    // Listen for incoming connections.
    l, err := net.Listen("tcp", "192.168.99.5:9977")
    if err != nil ...
    // Close the listener when the application closes.
    defer l.Close()
    fmt.Println("Listening on " + CONN_Host + ":" + CONN_PORT)
    for {
        // Listen for an incoming connection.
        conn, err := l.Accept()
        if err != nil ...

        //Handle connections in a new goroutine.
        go handleRequest(conn)
    }
}

// Handles incoming requests.
func handleRequest(conn net.Conn) {
    // Make a buffer to hold incoming data.
    buff := make([]byte, 1024)
    // Read the incoming connection into the buffer.
    _, err := conn.Read(buff)
    if err != nil {
        fmt.Printf("Error reading: %s.\n", err.Error())
    }
    // ReceiveSnapshot
    ds, err := zfs.ReceiveSnapshot(buff, "tank/replication")
    if err != nil {
        fmt.Printf("Error receiving: %s.\n", err.Error())
    }
    fmt.Printf("%s... done!\n", ds)
    // Send a response back to person contacting us.
    conn.Write([]byte("Received!"))
    // Close the connection when you're done with it.
    conn.Close()
}

ここで、github.com/mistifyio/go-zfs /zfs.goの関数ReceiveSnapshotを紹介します。

type command struct {
    Command string
    Stdin   io.Reader
    Stdout  io.Writer
}

func ReceiveSnapshot(input io.Reader, name string) (*Dataset, error) {
    c := command{Command: "zfs", Stdin: input}
    _, err := c.Run("receive", name)
    if err != nil {
        return nil, err
    }
    return GetDataset(name)
}

私はgolangpkgでio.Readerのドキュメントを見ました:

type Reader interface {
        Read(p []byte) (n int, err error)
}

エラーが発生するのはなぜですか...

  • zfs.ReceiveSnapshotの引数でタイプio.Readerとしてbuff(タイプ[] byte)を使用できません:[] byteはio.Readerを実装していません(Readメソッドがありません)

...私がgo installを作るとき?

6
icarbajo

リーダーのReaderメソッドが_[]byte_をパラメーターとして受け取るという理由だけで、_[]byte_がReadと同等であると考える場合、ロジックのステップが欠落していると思います。 。

明確にしようと思います:

ReceiveSnapshot関数は、パラメーターとしてReaderを想定しています。

_ReceiveSnapshot( input io.Reader ...
_

型がReaderインターフェースを満たすためには、その型自体がこの関数を実装する必要があります。

_Read(p []byte) (n int, err error)
_

型はReaderになるためにその関数をimplementする必要があることに注意してください。

_[]byte_Read関数を実装していませんReadへの引数がたまたま_[]byte_であるのは偶然です。

これを機能させるには、ReceiveSnapshotに適切なReaderを送信する必要があります。

幸いなことに、_[]byte_があり、それを読みたいというのは一般的な状況であるため、APIはこれを行う簡単な方法を提供します。

https://golang.org/pkg/bytes/#NewReader

ReceiveSnapshotだけでなく、bytes.NewReader(buff)buff関数に送信する必要があります。

13
eugenioy

短い答え_bytes.NewReader_ を使用して、バッファを Reader タイプでラップします

または、 _bytes.NewBuffer_ を使用して同様の効果を得ることができます。

ソースが文字列の場合は、 _strings.NewReader_ を使用できます。

読者のリストはどんどん増えています: https://golang.org/search?q=Read#Global


より深い質問の説明

より深い質問は次のとおりです:配列が_io.Reader_インターフェイスを直接サポートしないのはなぜですか?

_io.Reader_は、合計サイズが必ずしも事前にわかっているとは限らない一般的なデータストリームから読み取るという概念をサポートします。これをサポートするために、すべての入力データが使い果たされるまでReadが繰り返し呼び出されます。多くの言語では、同様の読み取り関数を少なくとも2回呼び出す必要があります。最後の呼び出しでは、ファイルの終わりを示すフラグが返されます。

2つの値(そのうちの1つはタイプ error )を返すことにより、Goは配列の読み取りをワンショットで完了することを可能にします。宛先バッファーは、使用可能なすべてのデータを消費するのに十分な大きさです-これは常に事前にわかっているわけではありません。

_io.Reader_ インターフェースは、Read()関数の署名と動作を指定します。

_func (T) Read(b []byte) (n int, err error)
_

読み取りは、指定されたバイトスライスにデータを入力し、入力されたバイト数とエラー値を返します。ストリームが終了すると、io.EOFエラーが返されます。

したがって、_io.Reader_インターフェイスの動作方法により、単純なバイトバッファでは実装できません。後続のRead()の呼び出し間の状態を記憶するには、ラッパー構造が必要です。

興味を引くために、これを実装する方法を示す例を次に示します...

_type MyReader struct {
    src []byte
    pos int
}

func (r *MyReader) Read(dst []byte) (n int, err error) {
    n = copy(dst, r.src[r.pos:])
    r.pos += n
    if r.pos == len(r.src) {
        return n, io.EOF
    }
    return
}

func NewMyReader(b []byte) *MyReader { return &MyReader{b, 0} }
_

また、Read()の_[]byte_パラメーターはソースではなく宛先バッファーであることに注意してください。

2
nobar