簡體   English   中英

不能使用(類型[] byte)作為類型io.Reader

[英]Cannot use (type []byte) as type 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)
}

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

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

為什么我收到錯誤...

  • 不能使用buff(type [] byte)作為zfs.ReceiveSnapshot參數中的類型io.Reader:[] byte不實現io.Reader(缺少Read方法)

...當我go install

當你認為[]byteReader等效時,我認為你錯過了邏輯中的一步,因為Reader的Read方法接收一個[]byte作為參數。

讓我試着澄清一下:

您的ReceiveSnapshot函數需要將Reader作為參數:

ReceiveSnapshot( input io.Reader ...

為了使類型能夠實現Reader接口,該類型本身應該實現此功能:

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

請注意,該類型應該實現該功能才能成為Reader

[]byte 不實現 Read功能。 只是巧合, Read的參數恰好是一個[]byte

為了使其正常工作,您需要向ReceiveSnapshot發送適當的Reader

幸運的是,有一個[]byte並想要讀取它是一種常見情況,因此API提供了一種簡單的方法:

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

你只需要將bytes.NewReader(buff)發送到你的ReceiveSnapshot函數而不僅僅是buff

簡答 :使用bytes.NewReader將緩沖區包裝在Reader類型中

或者,您可以使用具有類似效果的bytes.NewBuffer

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

讀者名單一直在繼續: https//golang.org/search?q = Read#Global


解釋更深層次的問題

更深層次的問題是:為什么數組不直接支持io.Reader接口?

io.Reader支持從一般數據流中讀取的概念,其總大小不一定是預先知道的 為了支持這一點,重復調用Read直到所有輸入數據都用完為止。 在許多語言中,類似的讀取函數必須至少調用兩次,其中最后的調用返回一個指示文件結尾的標志。

通過返回兩個值(其中一個是類型error ),Go可以一次性完成讀取數組的讀取, 但前提是目標緩沖區足夠大以消耗所有可用數據 - 這並不總是已知的提前。

io.Reader接口指定Read()函數的簽名和行為:

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

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

另請注意, Read()[]byte參數是目標緩沖區,而不是源。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM