Go语言核心36讲43-----io包中接口的好处与优势
上一篇文章中,我主要讲到了io.Reader
的扩展接口和实现类型。当然,io
代码包中的核心接口不止io.Reader
一个。
我们基于它引出的一条主线,只是io
包类型体系中的一部分。我们很有必要再从另一个角度去探索一下,以求对io
包有更加全面的了解。
下面的一个问题就与此有关。
知识扩展
问题:io
包中的接口都有哪些?它们之间都有着怎样的关系?
我们可以把没有嵌入其他接口并且只定义了一个方法的接口叫做简单接口。在io
包中,这样的接口一共有11个。
在它们之中,有的接口有着众多的扩展接口和实现类型,我们可以称之为核心接口。io
包中的核心接口只有3个,它们是:io.Reader
、io.Writer
和io.Closer
。
我们还可以把io
包中的简单接口分为四大类。这四大类接口分别针对于四种操作,即:读取、写入、关闭和读写位置设定。前三种操作属于基本的I/O操作。
关于读取操作,我们在前面已经重点讨论过核心接口io.Reader
。它在io
包中有5个扩展接口,并有6个实现类型。除了它,这个包中针对读取操作的接口还有不少。我们下面就来梳理一下。
首先来看io.ByteReader
和io.RuneReader
这两个简单接口。它们分别定义了一个读取方法,即:ReadByte
和ReadRune
。
但与io.Reader
接口中Read
方法不同的是,这两个读取方法分别只能够读取下一个单一的字节和Unicode字符。
我们之前讲过的数据类型strings.Reader
和bytes.Buffer
都是io.ByteReader
和io.RuneReader
的实现类型。
不仅如此,这两个类型还都实现了io.ByteScanner
接口和io.RuneScanner
接口。
io.ByteScanner
接口内嵌了简单接口io.ByteReader
,并定义了额外的UnreadByte
方法。如此一来,它就抽象出了一个能够读取和读回退单个字节的功能集。
与之类似,io.RuneScanner
内嵌了简单接口io.RuneReader
,并定义了额外的UnreadRune
方法。它抽象的是可以读取和读回退单个Unicode字符的功能集。
再来看io.ReaderAt
接口。它也是一个简单接口,其中只定义了一个方法ReadAt
。与我们在前面说过的读取方法都不同,ReadAt
是一个纯粹的只读方法。
它只去读取其所属值中包含的字节,而不对这个值进行任何的改动,比如,它绝对不能去修改已读计数的值。这也是io.ReaderAt
接口与其实现类型之间最重要的一个约定。
因此,如果仅仅并发地调用某一个值的ReadAt
方法,那么安全性应该是可以得到保障的。
另外,还有一个读取操作相关的接口我们没有介绍过,它就是io.WriterTo
。这个接口定义了一个名为WriteTo
的方法。
千万不要被它的名字迷惑,这个WriteTo
方法其实是一个读取方法。它会接受一个io.Writer
类型的参数值,并会把其所属值中的数据读出并写入到这个参数值中。
与之相对应的是io.ReaderFrom
接口。它定义了一个名叫ReadFrom
的写入方法。该方法会接受一个io.Reader
类型的参数值,并会从该参数值中读出数据,并写入到其所属值中。
值得一提的是,我们在前面用到过的io.CopyN
函数,在复制数据的时候会先检测其参数src
的值,是否实现了io.WriterTo
接口。如果是,那么它就直接利用该值的WriteTo
方法,把其中的数据拷贝给参数dst
代表的值。
类似的,这个函数还会检测dst
的值是否实现了io.ReaderFrom
接口。如果是,那么它就会利用这个值的ReadFrom
方法,直接从src
那里把数据拷贝进该值。
实际上,对于io.Copy
函数和io.CopyBuffer
函数来说也是如此,因为它们在内部做数据复制的时候用的都是同一套代码。
你也看到了,io.ReaderFrom
接口与io.WriterTo
接口对应得很规整。实际上,在io
包中,与写入操作有关的接口都与读取操作的相关接口有着一定的对应关系。下面,我们就来说说写入操作相关的接口。
首先当然是核心接口io.Writer
。基于它的扩展接口除了有我们已知的io.ReadWriter
、io.ReadWriteCloser
和io.ReadWriteSeeker
之外,还有io.WriteCloser
和io.WriteSeeker
。
我们之前提及的*io.pipe
就是io.ReadWriter
接口的实现类型。然而,在io
包中并没有io.ReadWriteCloser
接口的实现,它的实现类型主要集中在net
包中。
除此之外,写入操作相关的简单接口还有io.ByteWriter
和io.WriterAt
。可惜,io
包中也没有它们的实现类型。不过,有一个数据类型值得在这里提一句,那就是*os.File
。
这个类型不但是io.WriterAt
接口的实现类型,还同时实现了io.ReadWriteCloser
接口和io.ReadWriteSeeker
接口。也就是说,该类型支持的I/O操作非常的丰富。
io.Seeker
接口作为一个读写位置设定相关的简单接口,也仅仅定义了一个方法,名叫Seek
。
我在讲strings.Reader
类型的时候还专门说过这个Seek
方法,当时还给出了一个与已读计数估算有关的例子。该方法主要用于寻找并设定下一次读取或写入时的起始索引位置。
io
包中有几个基于io.Seeker
的扩展接口,包括前面讲过的io.ReadSeeker
和io.ReadWriteSeeker
,以及还未曾提过的io.WriteSeeker
。io.WriteSeeker
是基于io.Writer
和io.Seeker
的扩展接口。
我们之前多次提到的两个指针类型strings.Reader
和io.SectionReader
都实现了io.Seeker
接口。顺便说一句,这两个类型也都是io.ReaderAt
接口的实现类型。
最后,关闭操作相关的接口io.Closer
非常通用,它的扩展接口和实现类型都不少。我们单从名称上就能够一眼看出io
包中的哪些接口是它的扩展接口。至于它的实现类型,io
包中只有io.PipeReader
和io.PipeWriter
。
总结
我们来总结一下这两篇的内容。在Go语言中,对接口的扩展是通过接口类型之间的嵌入来实现的,这也常被叫做接口的组合。而io
代码包恰恰就可以作为接口扩展的一个标杆,它可以成为我们运用这种技巧时的一个参考标准。
在本文中,我根据接口定义的方法的数量以及是否有接口嵌入,把io
包中的接口分为了简单接口和扩展接口。
同时,我又根据这些简单接口的扩展接口和实现类型的数量级,把它们分为了核心接口和非核心接口。
在io
包中,称得上核心接口的简单接口只有3个,即:io.Reader
、io.Writer
和io.Closer
。这些核心接口在Go语言标准库中的实现类型都在200个以上。
另外,根据针对的I/O操作的不同,我还把简单接口分为了四大类。这四大类接口针对的操作分别是:读取、写入、关闭和读写位置设定。
其中,前三种操作属于基本的I/O操作。基于此,我带你梳理了每个类别的简单接口,并讲解了它们在io
包中的扩展接口,以及具有代表性的实现类型。
( io包中的接口体系)
除此之外,我还从多个维度为你描述了一些重要程序实体的功用和机理,比如:数据段读取器io.SectionReader
、作为同步内存管道核心实现的io.pipe
类型,以及用于数据拷贝的io.CopyN
函数,等等。
我如此详尽且多角度的阐释,正是为了让你能够记牢io
代码包中有着网状关系的接口和数据类型。我希望这个目的已经达到了,最起码,本文可以作为你深刻记忆它们的开始。
最后再强调一下,io
包中的简单接口共有11个。其中,读取操作相关的接口有5个,写入操作相关的接口有4个,而与关闭操作有关的接口只有1个,另外还有一个读写位置设定相关的接口。
此外,io
包还包含了9个基于这些简单接口的扩展接口。你需要在今后思考和实践的是,你在什么时候应该编写哪些数据类型实现io
包中的哪些接口,并以此得到最大的好处。
思考题
今天的思考题是:io
包中的同步内存管道的运作机制是什么?
Go语言核心36讲43-----io包中接口的好处与优势的更多相关文章
- Go语言核心36讲(Go语言实战与应用十八)--学习笔记
40 | io包中的接口和工具 (上) 我们在前几篇文章中,主要讨论了strings.Builder.strings.Reader和bytes.Buffer这三个数据类型. 知识回顾 还记得吗?当时我 ...
- Go语言核心36讲(Go语言进阶技术八)--学习笔记
14 | 接口类型的合理运用 前导内容:正确使用接口的基础知识 在 Go 语言的语境中,当我们在谈论"接口"的时候,一定指的是接口类型.因为接口类型与其他数据类型不同,它是没法被实 ...
- Go语言核心36讲(Go语言实战与应用二十二)--学习笔记
44 | 使用os包中的API (上) 我们今天要讲的是os代码包中的 API.这个代码包可以让我们拥有操控计算机操作系统的能力. 前导内容:os 包中的 API 这个代码包提供的都是平台不相关的 A ...
- Go语言核心36讲(Go语言实战与应用十九)--学习笔记
41 | io包中的接口和工具 (下) 上一篇文章中,我主要讲到了io.Reader的扩展接口和实现类型.当然,io代码包中的核心接口不止io.Reader一个. 我们基于它引出的一条主线,只是io包 ...
- Go语言核心36讲(Go语言实战与应用二十一)--学习笔记
43 | bufio包中的数据类型(下) 在上一篇文章中,我提到了bufio包中的数据类型主要有Reader.Scanner.Writer和ReadWriter.并着重讲到了bufio.Reader类 ...
- Go语言核心36讲(新年彩蛋)--学习笔记
新年彩蛋 | 完整版思考题答案 基础概念篇 Go 语言在多个工作区中查找依赖包的时候是以怎样的顺序进行的? 答:你设置的环境变量GOPATH的值决定了这个顺序.如果你在GOPATH中设置了多个工作区, ...
- Go语言核心36讲(Go语言实战与应用二十)--学习笔记
42 | bufio包中的数据类型 (上) 今天,我们来讲另一个与 I/O 操作强相关的代码包bufio.bufio是"buffered I/O"的缩写.顾名思义,这个代码包中的程 ...
- Go语言核心36讲(Go语言实战与应用二十三)--学习笔记
45 | 使用os包中的API (下) 我们在上一篇文章中.从"os.File类型都实现了哪些io包中的接口"这一问题出发,介绍了一系列的相关内容.今天我们继续围绕这一知识点进行扩 ...
- Go语言核心36讲(Go语言实战与应用三)--学习笔记
25 | 更多的测试手法 在本篇文章,我会继续为你讲解更多更高级的测试方法.这会涉及testing包中更多的 API.go test命令支持的,更多标记更加复杂的测试结果,以及测试覆盖度分析等等. 前 ...
- Go语言核心36讲(Go语言实战与应用四)--学习笔记
26 | sync.Mutex与sync.RWMutex 从本篇文章开始,我们将一起探讨 Go 语言自带标准库中一些比较核心的代码包.这会涉及这些代码包的标准用法.使用禁忌.背后原理以及周边的知识. ...
随机推荐
- Linux之NFS服务搭建及autofs服务搭建
NFS 网络文件系统,英文Network File System(NFS),是由SUN公司研制的UNIX表示层协议(presentation layer protocol),能使使用者访问网络上别处的 ...
- KingbaseES批量数据加载的实践技巧
有时,KingbaseES数据库需要在单个或最少的步骤中导入大量数据,这通常称为批量数据导入.其中数据源通常是一个或多个大文件,这个过程有时可能非常慢. 造成性能不佳的原因有很多:索引.触发器.外键. ...
- 容器化|自建 MySQL 集群迁移到 Kubernetes
背景 如果你有自建的 MySQL 集群,并且已经感受到了云原生的春风拂面,想将数据迁移到 Kubernetes 上,那么这篇文章可以给你一些思路. 文中将自建 MySQL 集群数据,在线迁移到 Kub ...
- Windows服务器TLS协议
今天在Windows Admin Center里试图安装扩展插件的时候遇到一个问题.在可用插件里没有任何显示,包括各种微软自己开发的插件. 在Feeds里删除默认的链接,重新添加的时候也会遇到报错.说 ...
- day40-网络编程02
Java网络编程02 4.TCP网络通信编程 基本介绍 基于客户端--服务端的网络通信 底层使用的是TCP/IP协议 应用场景举例:客户端发送数据,服务端接收并显示控制台 基于Scoket的TCP编程 ...
- Python数据科学手册-Numpy数组的计算:比较、掩码和布尔逻辑,花哨的索引
Numpy的通用函数可以用来替代循环, 快速实现数组的逐元素的 运算 同样,使用其他通用函数实现数组的逐元素的 比较 < > 这些运算结果 是一个布尔数据类型的数组. 有6种标准的比较操作 ...
- 1_Layui
一. 引言 官网: https://www.layui.com/ 在官网首页, 可以很方便的下载Layui Layui是一款经典模块化前端UI框架, 我们只需要定义简单的HTML,CSS,JS即可实现 ...
- 5_项目实战MyShop
一. 网上商城 1.1 商城类别 B2B 商家对商家 B2C 商家对客户 C2C 客户对客户 O2O 线上线下相结合 1.2 商城常见模块 后台常见功能模块 商品管理 包括后台商品库存管理, 上货, ...
- 使用css制作轮播图
<!--HTML代码--> <!DOCTYPE html> <html lang="en"><head> <meta char ...
- Java后端开发——美团(牛客)
Java后端开发--美团(牛客) Java的基本数据类型,各自的字节数 老生常谈,不多说了. 类型 字节数 byte 1字节 short 2字节 int 4字节 long 8字节 float 4字 ...