Go语言中的io.Reader和io.Writer以及它们的实现

uu434zo56t 3年前
   <p>在使用Go语言的过程中,无论你是实现web应用程序,还是控制台输入输出,又或者是网络操作,不可避免的会遇到IO操作,使用到io.Reader和io.Writer接口。也也许对这两个接口和相关的一些接口很熟悉了,但是你脑海里确很难形成一个对io接口的继承关系整天的概貌,原因在于godoc缺省并没有像javadoc一样显示官方库继承关系,这导致了我们对io接口的继承关系记忆不深,在使用的时候还经常需要翻文档加深记忆。本文试图梳理清楚Go io接口的继承关系,提供一个io接口的全貌。</p>    <h3><strong>io接口回顾</strong></h3>    <p>首先我们回顾一下几个常用的io接口。标准库的实现是将功能细分,每个最小粒度的功能定义成一个接口,然后接口可以组成成更多功能的接口。</p>    <p>最小粒度的接口</p>    <pre>  <code class="language-php">typeReaderinterface{   Read(p []byte) (nint, err error)  }  </code></pre>    <pre>  <code class="language-php">typeWriterinterface{   Write(p []byte) (nint, err error)  }  </code></pre>    <pre>  <code class="language-php">typeCloserinterface{   Close() error  }  </code></pre>    <pre>  <code class="language-php">typeSeekerinterface{   Seek(offset int64, whenceint) (int64, error)  }  </code></pre>    <pre>  <code class="language-php">typeReaderFrominterface{   ReadFrom(r Reader) (n int64, err error)  }  </code></pre>    <pre>  <code class="language-php">typeWriterTointerface{   WriteTo(w Writer) (n int64, err error)  }  </code></pre>    <pre>  <code class="language-php">typeReaderAtinterface{   ReadAt(p []byte, offint64) (nint, err error)  }  </code></pre>    <pre>  <code class="language-php">typeWriterAtinterface{   WriteAt(p []byte, offint64) (nint, err error)  }  </code></pre>    <p>以及</p>    <pre>  <code class="language-php">typeByteReaderinterface{   ReadByte() (byte, error)  }  </code></pre>    <pre>  <code class="language-php">typeByteWriterinterface{   WriteByte(c byte) error  }  </code></pre>    <p>ByteScanner比ByteReader多了一个 UnreadByte 方法。</p>    <pre>  <code class="language-php">typeByteScannerinterface{   ByteReader   UnreadByte() error  }  </code></pre>    <pre>  <code class="language-php">typeRuneReaderinterface{   ReadRune() (r rune, sizeint, err error)  }  </code></pre>    <pre>  <code class="language-php">typeRuneScannerinterface{   RuneReader   UnreadRune() error  }  </code></pre>    <p><strong>组合接口</strong></p>    <p>Go标准库还定义了一些由上面的单一职能的接口组合而成的接口。</p>    <pre>  <code class="language-php">typeReadCloserinterface{   Reader   Closer  }  </code></pre>    <pre>  <code class="language-php">typeReadSeekerinterface{   Reader   Seeker  }  </code></pre>    <pre>  <code class="language-php">typeReadWriterinterface{   Reader   Writer  }  </code></pre>    <pre>  <code class="language-php">typeReadWriteCloserinterface{   Reader   Writer   Closer  }  </code></pre>    <pre>  <code class="language-php">typeReadWriteSeekerinterface{   Reader   Writer   Seeker  }  </code></pre>    <pre>  <code class="language-php">typeWriteCloserinterface{   Writer   Closer  }  </code></pre>    <pre>  <code class="language-php">typeWriteSeekerinterface{   Writer   Seeker  }  </code></pre>    <p>从它们的定义上可以看出,它们是最小粒度的组合。</p>    <p><strong>最小接口的扩展</strong></p>    <p>有些结构体struct实现并且扩展了接口,这些结构体是。</p>    <pre>  <code class="language-php">typeLimitedReaderstruct{   R Reader // underlying reader   N int64// max bytes remaining  }  </code></pre>    <pre>  <code class="language-php">typePipeReaderstruct{  // contains filtered or unexported fields  }  </code></pre>    <pre>  <code class="language-php">typePipeWriterstruct{  // contains filtered or unexported fields  }  </code></pre>    <pre>  <code class="language-php">typeSectionReaderstruct{  // contains filtered or unexported fields  }  </code></pre>    <p>下面我会将它们的继承关系画出来。</p>    <p>一些辅助方法</p>    <p>一些辅助方法可以生成特殊类型的Reader或者Writer:</p>    <pre>  <code class="language-php">funcLimitReader(r Reader, nint64) Reader  funcMultiReader(readers ...Reader) Reader  funcTeeReader(r Reader, w Writer) Reader    funcMultiWriter(writers ...Writer) Writer  </code></pre>    <h3><strong>继承关系</strong></h3>    <p>当然,Go语言中并没有Java中那样的继承关系,而是基于duck type形式实现,我用下图尝试展示Go io接口的继承关系。</p>    <p><img src="https://simg.open-open.com/show/d91768f1d52c079f5b016bbfb4c98bd6.png"></p>    <p>其中黄色是 bufio 包下的类型,</p>    <p>绿色是 archive.tar 包下的类型,</p>    <p>蓝色是 bytes 包下的类型,</p>    <p>粉红色是 strings 包下的类型,</p>    <p>紫色是 crypto.tls 包下的类型。</p>    <p>Rand 是 math.rand 包下的类型。</p>    <p>File 是 os 包下的内容。</p>    <p>`Rand`左边的那个 Reader 是 image.jpeg 下的内容。</p>    <p>我们最常用的是包 io 、 bytes 、 bufio 下的类型,所以这几个包下的类型要记牢,在第三库中经常会出现它们的身影。</p>    <p>上图中并没有把 mime/multipart.File 和 net/http.File 列出来,主要是图太复杂了,它们实现的接口和 os.File 类似。</p>    <p>当然你可能会问,你怎么整理的它们的继承关系?事实上,你可以通过 godoc -analysis=type -http=:6060 生成带继承关系的Go doc,并且它还可以将你本地下载的库中的继承关系也显示出来。</p>    <p><img src="https://simg.open-open.com/show/5d34a25b7e3eeb96615628e00258fdd0.png"></p>    <h3>参考文档</h3>    <ol>     <li><a href="/misc/goto?guid=4959677507350589266" rel="nofollow,noindex">https://golang.org/pkg/io/</a></li>     <li><a href="/misc/goto?guid=4959677507442695818" rel="nofollow,noindex">https://golang.org/pkg/bufio/</a></li>     <li><a href="/misc/goto?guid=4959677507530074606" rel="nofollow,noindex">https://golang.org/pkg/bytes/</a></li>     <li><a href="/misc/goto?guid=4959677507619899519" rel="nofollow,noindex">https://medium.com/@benbjohnson/go-walkthrough-io-package-8ac5e95a9fbd#.er7vmwvb3</a></li>     <li><a href="/misc/goto?guid=4959677507701812033" rel="nofollow,noindex">https://medium.com/@blumenmann/a-simple-beginners-tutorial-to-io-writer-in-golang-2a13bfefea02#.sm0gq7rn0</a></li>     <li><a href="/misc/goto?guid=4959677507793765749" rel="nofollow,noindex">https://www.reddit.com/r/golang/comments/4z2eo2/noob_question_how_to_discover_interface/</a></li>    </ol>    <p> </p>    <p>来自:http://colobu.com/2016/08/29/go-io-Reader-and-io-Writer/</p>    <p> </p>