douguanyun2169 2017-05-19 09:11
浏览 932
已采纳

无法将([] byte类型)用作io.Reader类型

I don't understand the error, this is my main.go that I execute in the machine "A":

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.
", err.Error())
    }
    // ReceiveSnapshot
    ds, err := zfs.ReceiveSnapshot(buff, "tank/replication")
    if err != nil {
        fmt.Printf("Error receiving: %s.
", err.Error())
    }
    fmt.Printf("%s... done!
", ds)
    // Send a response back to person contacting us.
    conn.Write([]byte("Received!"))
    // Close the connection when you're done with it.
    conn.Close()
}

Now, I show you the function ReceiveSnapshot from github.com/mistifyio/go-zfs/zfs.go:

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)
}

I have seen in golang pkg the doc of io.Reader:

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

Why do I receive the error...

  • cannot use buff (type []byte) as type io.Reader in argument to zfs.ReceiveSnapshot: []byte does not implement io.Reader (missing Read method)

...when I make go install ?

  • 写回答

2条回答 默认 最新

  • doulun5683 2017-05-19 12:23
    关注

    I think you are missing a step in your logic when you think that []byte would be equivalent to Reader just because the Reader's Read method receives a []byte as a parameter.

    Let me try to clarify:

    Your ReceiveSnapshot function expects a Reader as a parameter:

    ReceiveSnapshot( input io.Reader ...
    

    In order for a type to fulfil the Reader interface, that type should itself implement this function:

    Read(p []byte) (n int, err error)
    

    Note that the type should implement that function in order to be a Reader.

    []byte does not implement a Read function. It is just a coincidence that the argument to Read happens to be a []byte.

    In order for this to work, you need to send ReceiveSnapshot a proper Reader.

    Luckily for you, having a []byte and wanting to Read for it is a common situation so the API provides an easy way to do this:

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

    You just need to send bytes.NewReader(buff) to your ReceiveSnapshot function instead of just buff.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
  • douzai6337 2019-08-21 01:36
    关注

    Short answer: Wrap your buffer in a Reader type by using bytes.NewReader

    Alternatively, you could use bytes.NewBuffer with similar effect.

    If the source is a string, you can use strings.NewReader.

    The list of Readers goes on and on: https://golang.org/search?q=Read#Global


    Explanation of the deeper question

    The deeper question being: Why doesn't an array support the io.Reader interface directly?

    io.Reader supports the concept of reading from a general data stream for which the total size is not necessarily known in advance. In order to support this, Read is called repeatedly until all input data is exhausted. In many languages, similar read functions must be called at least twice, where the final call returns a flag indicating end-of-file.

    By returning two values (one of which is type error), Go makes it possible for reading of arrays to complete in one-shot, but only if the destination buffer is large enough to consume all available data -- which isn't always known in advance.

    The io.Reader interface specifies the signature and behavior of the Read() function:

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

    Read populates the given byte slice with data and returns the number of bytes populated and an error value. It returns an io.EOF error when the stream ends.

    So due to the way the io.Reader interface works, a simple byte buffer is not capable of implementing it. A wrapper structure is required in order to remember the state between subsequent calls to Read().

    For the sake of interest, here's an example showing how that can be implemented...

    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} }
    

    Notice, also, that the []byte parameter to Read() is the destination buffer, not the source.

    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 复杂表达式求值程序里的函数优先级问题
  • ¥15 求密码学的客成社记ji着用
  • ¥35 POI导入树状结构excle
  • ¥15 初学者c语言题目解答
  • ¥15 div editable中的光标问题
  • ¥15 mysql报错1415Not allowed to return a result set from a trigger 不知如何修改
  • ¥60 Python输出Excel数据整理,算法较为复杂
  • ¥15 回答几个问题 关于数据库
  • ¥15 51单片机串口通信问题,未完成且要修改
  • ¥15 百鸡问题 c++编程问题(相关搜索:输出数据)