不能使用(类型[] byte)作为类型io.Reader

ica*_*ajo 5 io byte go 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()
}
Run Code Online (Sandbox Code Playgroud)

现在,我向您展示来自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)
}
Run Code Online (Sandbox Code Playgroud)

我在golang pkg中看到了io.Reader的文档:

type Reader interface {
        Read(p []byte) (n int, err error)
}
Run Code Online (Sandbox Code Playgroud)

为什么我收到错误...

  • 不能使用buff(type [] byte)作为zfs.ReceiveSnapshot参数中的类型io.Reader:[] byte不实现io.Reader(缺少Read方法)

......当我做的时候go install

eug*_*ioy 11

我认为你缺少你的逻辑了一步,当你认为[]byte将相当于Reader只是因为读者的Read方法接收[]byte作为参数.

让我试着澄清一下:

您的ReceiveSnapshot函数需要Reader一个参数:

ReceiveSnapshot( input io.Reader ...
Run Code Online (Sandbox Code Playgroud)

为了使类型能够实现Reader接口,该类型本身应该实现此功能:

Read(p []byte) (n int, err error)
Run Code Online (Sandbox Code Playgroud)

请注意,该类型应该实现该功能才能成为a Reader.

[]byte 没有实现一个Read功能.这个论点Read碰巧是一个巧合而已[]byte.

为了使其工作,您需要发送ReceiveSnapshot一个适当的Reader.

幸运的是,有一个[]byte并且想要读取它是一种常见的情况,因此API提供了一种简单的方法:

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

您只需要发送bytes.NewReader(buff)到您的ReceiveSnapshot功能而不仅仅是buff.


nob*_*bar 6

简短的回答:使用Reader类型将缓冲区包装起来bytes.NewReader

或者,您可以使用bytes.NewBuffer类似的效果。

如果源是字符串,则可以使用strings.NewReader.

读者名单不胜枚举: https: //golang.org/search?q =Read#Global


更深层次问题的解释

更深层次的问题是:为什么数组不io.Reader直接支持接口?

io.Reader支持从通用数据流中读取的概念,该数据流的总大小不一定事先已知。为了支持这一点,Read重复调用,直到所有输入数据耗尽。在许多语言中,类似的读取函数必须至少调用两次,其中最后一次调用返回一个指示文件结束的标志。

通过返回两个值(其中一个是 type error),Go 可以一次性完成数组的读取,但前提是目标缓冲区足够大以消耗所有可用数据——这在进步。

接口io.Reader指定函数的签名和行为Read()

func (T) Read(b []byte) (n int, err error)
Run Code Online (Sandbox Code Playgroud)

Read 用数据填充给定的字节片,并返回填充的字节数和错误值。当流结束时,它返回 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} }
Run Code Online (Sandbox Code Playgroud)

另请注意,参数[]bytetoRead()是目标缓冲区,而不是源缓冲区。