前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[译] Golang Reader 接口实现

[译] Golang Reader 接口实现

作者头像
柳公子
发布2020-12-16 18:20:54
2K0
发布2020-12-16 18:20:54
举报
文章被收录于专栏:PhpZendoPhpZendoPhpZendo

Golang Reader 接口实现

尽管本文探讨的是如何实现 io.Reader 接口,但是作为实现接口的一般套路也是有意义的。在讨论接口实现的这个主题时,我发现多数文章所列举的示例都脱离的现实,比如去实现一个 Animal 接口。

首先,我们看下如何编写代码的数据接口才能满足实现 io.Reader 接口的条件。从 go 文档我们可以看到。

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

这看起来很简单,我们要做的就是去实现一个 Read 方法。本文我将实现一个 Stringer 数据结构,当调用 read 方法时,它将输出字符串。它看起来如下。

type Stringer struct {
    stringer string
    read bool
}

现在我们要去实现 io.Reader 接口,仅需要创建 Read 方法,接口签名是一个 slice 的 bytes 数据,返回 int 和 error 数据。

func (s Stringer) Read(p []bytes) (n int, err error) {

}

如果你之前使用过 go,你可能已经发现这段代码是无法工作的。由于它没有指针指向底层数据结构,所以我们无法跟踪它已经读取过的内容。这个问题的原因是当注入 io.ReadAll 多次调用 Read 方法时会期望在读到文件结束是收到一个错误通知。如果无法实现你的程序会耗尽内存。

我们真正想实现的是有如下函数签名的方法。

func (s *Stringer) Read(p []bytes) (n int, err error) {

}

它的问题在于,当你实现这个方法并将他作为参数传递个接收 io.Reader 类型的方法时,你会受到下面的信息。这里是完整代码的链接

Stringer does not implement io.Reader (Read method has pointer receiver)

译注:代码片段:

package main

import "io/ioutil"

type Stringer struct {
    name string
    done bool
}

func (s *Stringer) Read(p []byte) (n int, err error) {
    return 0, nil
}

func main() {
    s := Stringer{}
    ioutil.ReadAll(s)
}

解决的方法是,创建一个指针类型作为参数传入。不过它会抛出另一个错误,除非你正确实现 Reader 方法 http://play.golang.org/p/gyMcTp2ALX

译注:代码片段:

package main

import  "io/ioutil"
import "io"

type Stringer struct {
    name string
    done bool
}

func (s *Stringer) Read(p []byte) (n int, err error) {
    return 0, io.EOF
}

func main() {
    s := &Stringer{}
    ioutil.ReadAll(s)
}

现在来实现真正可以工作的 Read 方法。

func (r *Reader) Read(p []byte) (n int, err error) {
    if r.done {
            return 0, io.EOF
    }
    for i, b := range []byte(r.read) {
            p[i] = b
    }
    r.done = true
    return len(r.read), nil
}

如你所见,正因为我们可以操作底层数据结构,我们才能够标记合适 read 应该停止被调用。完整的实现类似于 http://play.golang.org/p/ejpUVOx8jR

译注:代码片段:

package main

import "io/ioutio"
import "io"
import "log"

type Reader struct {
    read string
    done bool
}

func NewReader(toRead string) *Reader {
    return &Reader{toRead, false}
}

func (r *Reader) Read (p []byte) (n int, err error) {
    if r.done {
        return 0, io.EOF
    }

    for i, b := range []byte(r.read) {
        p[i] = b
    }

    r.done = true
    return len(r.read), nil
}

func main() {
    M := NewReader ("test")
    stuff, _ := ioutil.ReadAll(M)
    log.Printf("%s", stuff)
}

原文: Golang’s Reader Interface

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020年12月14日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档