首页 > 其他分享 >Go语言核心36讲 41 | io包中的接口和工具 (下)

Go语言核心36讲 41 | io包中的接口和工具 (下)

时间:2024-01-21 22:26:11浏览次数:35  
标签:包中 读取 36 接口 41 io Reader 类型

上一篇文章中,我主要讲到了io.Reader的扩展接口和实现类型。当然,io代码包中的核心接口不止io.Reader一个。

我们基于它引出的一条主线,只是io包类型体系中的一部分。我们很有必要再从另一个角度去探索一下,以求对io包有更加全面的了解。

下面的一个问题就与此有关。

知识扩展

问题:io包中的接口都有哪些?它们之间都有着怎样的关系?

我们可以把没有嵌入其他接口并且只定义了一个方法的接口叫做简单接口。在io包中,这样的接口一共有11个。

在它们之中,有的接口有着众多的扩展接口和实现类型,我们可以称之为核心接口io包中的核心接口只有3个,它们是:io.Readerio.Writerio.Closer

我们还可以把io包中的简单接口分为四大类。这四大类接口分别针对于四种操作,即:读取、写入、关闭和读写位置设定。前三种操作属于基本的I/O操作。

关于读取操作,我们在前面已经重点讨论过核心接口io.Reader。它在io包中有5个扩展接口,并有6个实现类型。除了它,这个包中针对读取操作的接口还有不少。我们下面就来梳理一下。

首先来看io.ByteReaderio.RuneReader这两个简单接口。它们分别定义了一个读取方法,即:ReadByteReadRune

但与io.Reader接口中Read方法不同的是,这两个读取方法分别只能够读取下一个单一的字节和Unicode字符。

我们之前讲过的数据类型strings.Readerbytes.Buffer都是io.ByteReaderio.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.ReadWriterio.ReadWriteCloserio.ReadWriteSeeker之外,还有io.WriteCloserio.WriteSeeker

我们之前提及的*io.pipe就是io.ReadWriter接口的实现类型。然而,在io包中并没有io.ReadWriteCloser接口的实现,它的实现类型主要集中在net包中。

除此之外,写入操作相关的简单接口还有io.ByteWriterio.WriterAt。可惜,io包中也没有它们的实现类型。不过,有一个数据类型值得在这里提一句,那就是*os.File

这个类型不但是io.WriterAt接口的实现类型,还同时实现了io.ReadWriteCloser接口和io.ReadWriteSeeker接口。也就是说,该类型支持的I/O操作非常的丰富。

io.Seeker接口作为一个读写位置设定相关的简单接口,也仅仅定义了一个方法,名叫Seek

我在讲strings.Reader类型的时候还专门说过这个Seek方法,当时还给出了一个与已读计数估算有关的例子。该方法主要用于寻找并设定下一次读取或写入时的起始索引位置。

io包中有几个基于io.Seeker的扩展接口,包括前面讲过的io.ReadSeekerio.ReadWriteSeeker,以及还未曾提过的io.WriteSeekerio.WriteSeeker是基于io.Writerio.Seeker的扩展接口。

我们之前多次提到的两个指针类型strings.Readerio.SectionReader都实现了io.Seeker接口。顺便说一句,这两个类型也都是io.ReaderAt接口的实现类型。

最后,关闭操作相关的接口io.Closer非常通用,它的扩展接口和实现类型都不少。我们单从名称上就能够一眼看出io包中的哪些接口是它的扩展接口。至于它的实现类型,io包中只有io.PipeReaderio.PipeWriter

总结

我们来总结一下这两篇的内容。在Go语言中,对接口的扩展是通过接口类型之间的嵌入来实现的,这也常被叫做接口的组合。而io代码包恰恰就可以作为接口扩展的一个标杆,它可以成为我们运用这种技巧时的一个参考标准。

在本文中,我根据接口定义的方法的数量以及是否有接口嵌入,把io包中的接口分为了简单接口和扩展接口。

同时,我又根据这些简单接口的扩展接口和实现类型的数量级,把它们分为了核心接口和非核心接口。

io包中,称得上核心接口的简单接口只有3个,即:io.Readerio.Writerio.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,接口,41,io,Reader,类型
From: https://www.cnblogs.com/rskd/p/17978557/go-yu-yan-he-xin36jiang-41--io-bao-zhong-de-jie-ko

相关文章

  • Go语言核心36讲 40 | io包中的接口和工具 (上)
    我们在前几篇文章中,主要讨论了strings.Builder、strings.Reader和bytes.Buffer这三个数据类型。知识回顾还记得吗?当时我还问过你“它们都实现了哪些接口”。在我们继续讲解io包中的接口和工具之前,我先来解答一下这个问题。strings.Builder类型主要用于构建字符串,它的指针类型......
  • Go语言核心36讲 44 | 使用os包中的API (上)
    我们今天要讲的是os代码包中的API。这个代码包可以让我们拥有操控计算机操作系统的能力。前导内容:os包中的API这个代码包提供的都是平台不相关的API。那么说,什么叫平台不相关的API呢?它的意思是:这些API基于(或者说抽象自)操作系统,为我们使用操作系统的功能提供高层次的支持,但是,......
  • Go语言核心36讲 43 | bufio包中的数据类型(下)
    你好,我是郝林,我今天继续分享bufio包中的数据类型。在上一篇文章中,我提到了bufio包中的数据类型主要有Reader、Scanner、Writer和ReadWriter。并着重讲到了bufio.Reader类型与bufio.Writer类型,今天,我们继续专注bufio.Reader的内容来进行学习。知识扩展问题:bufio.Reader类型读......
  • Go语言核心36讲 46 | 访问网络服务
    你真的很棒,已经跟着我一起从最开始初识Go语言,一步一步地走到了这里。在这之前的几十篇文章中,我向你一点一点地介绍了很多Go语言的核心知识,以及一些最最基础的标准库代码包。我想,你已经完全有能力独立去做一些事情了。为了激发你更多的兴趣,我还打算用几篇文章来说说Go语言的网......
  • Go语言核心36讲 45 | 使用os包中的API (下)
    你好,我是郝林,今天我们继续分享使用os包中的API。我们在上一篇文章中。从“os.File类型都实现了哪些io包中的接口”这一问题出发,介绍了一系列的相关内容。今天我们继续围绕这一知识点进行扩展。知识扩展问题1:可应用于File值的操作模式都有哪些?针对File值的操作模式主要有只读......
  • Go语言核心36讲 49 | 程序性能分析基础(下)
    你好,我是郝林,今天我们继续分享程序性能分析基础的内容。在上一篇文章中,我们围绕着“怎样让程序对CPU概要信息进行采样”这一问题进行了探讨,今天,我们再来一起看看它的拓展问题。知识扩展问题1:怎样设定内存概要信息的采样频率?针对内存概要信息的采样会按照一定比例收集Go程序......
  • Go语言核心36讲 48 | 程序性能分析基础(上)
    作为拾遗的部分,今天我们来讲讲与Go程序性能分析有关的基础知识。Go语言为程序开发者们提供了丰富的性能分析API,和非常好用的标准工具。这些API主要存在于:runtime/pprof;net/http/pprof;runtime/trace;这三个代码包中。另外,runtime代码包中还包含了一些更底层的API。它们可......
  • Go语言核心36讲 47 | 基于HTTP协议的网络服务
    我们在上一篇文章中简单地讨论了网络编程和socket,并由此提及了Go语言标准库中的syscall代码包和net代码包。我还重点讲述了net.Dial函数和syscall.Socket函数的参数含义。前者间接地调用了后者,所以正确理解后者,会对用好前者有很大裨益。之后,我们把视线转移到了net.DialTimeout......
  • Go语言核心36讲 19 | 错误处理(上)
    提到Go语言中的错误处理,我们其实已经在前面接触过几次了。比如,我们声明过error类型的变量err,也调用过errors包中的New函数。今天,我会用这篇文章为你梳理Go语言错误处理的相关知识,同时提出一些关键问题并与你一起探讨。我们说过error类型其实是一个接口类型,也是一个Go语言的内......
  • Go语言核心36讲 24 | 测试的基本规则和流程(下)
    你好,我是郝林。今天我分享的主题是测试的基本规则和流程的(下)篇。Go语言是一门很重视程序测试的编程语言,所以在上一篇中,我与你再三强调了程序测试的重要性,同时,也介绍了关于gotest命令的基本规则和主要流程的内容。今天我们继续分享测试的基本规则和流程。本篇代码和指令较多,你......