Go語言中的io.Reader和io.Writer以及它們的實現
在使用Go語言的過程中,無論你是實現web應用程序,還是控制臺輸入輸出,又或者是網絡操作,不可避免的會遇到IO操作,使用到io.Reader和io.Writer接口。也也許對這兩個接口和相關的一些接口很熟悉了,但是你腦海里確很難形成一個對io接口的繼承關系整天的概貌,原因在于godoc缺省并沒有像javadoc一樣顯示官方庫繼承關系,這導致了我們對io接口的繼承關系記憶不深,在使用的時候還經常需要翻文檔加深記憶。本文試圖梳理清楚Go io接口的繼承關系,提供一個io接口的全貌。
io接口回顧
首先我們回顧一下幾個常用的io接口。標準庫的實現是將功能細分,每個最小粒度的功能定義成一個接口,然后接口可以組成成更多功能的接口。
最小粒度的接口
typeReaderinterface{
Read(p []byte) (nint, err error)
}
typeWriterinterface{
Write(p []byte) (nint, err error)
}
typeCloserinterface{
Close() error
}
typeSeekerinterface{
Seek(offset int64, whenceint) (int64, error)
}
typeReaderFrominterface{
ReadFrom(r Reader) (n int64, err error)
}
typeWriterTointerface{
WriteTo(w Writer) (n int64, err error)
}
typeReaderAtinterface{
ReadAt(p []byte, offint64) (nint, err error)
}
typeWriterAtinterface{
WriteAt(p []byte, offint64) (nint, err error)
}
以及
typeByteReaderinterface{
ReadByte() (byte, error)
}
typeByteWriterinterface{
WriteByte(c byte) error
}
ByteScanner比ByteReader多了一個 UnreadByte 方法。
typeByteScannerinterface{
ByteReader
UnreadByte() error
}
typeRuneReaderinterface{
ReadRune() (r rune, sizeint, err error)
}
typeRuneScannerinterface{
RuneReader
UnreadRune() error
}
組合接口
Go標準庫還定義了一些由上面的單一職能的接口組合而成的接口。
typeReadCloserinterface{
Reader
Closer
}
typeReadSeekerinterface{
Reader
Seeker
}
typeReadWriterinterface{
Reader
Writer
}
typeReadWriteCloserinterface{
Reader
Writer
Closer
}
typeReadWriteSeekerinterface{
Reader
Writer
Seeker
}
typeWriteCloserinterface{
Writer
Closer
}
typeWriteSeekerinterface{
Writer
Seeker
}
從它們的定義上可以看出,它們是最小粒度的組合。
最小接口的擴展
有些結構體struct實現并且擴展了接口,這些結構體是。
typeLimitedReaderstruct{
R Reader // underlying reader
N int64// max bytes remaining
}
typePipeReaderstruct{
// contains filtered or unexported fields
}
typePipeWriterstruct{
// contains filtered or unexported fields
}
typeSectionReaderstruct{
// contains filtered or unexported fields
}
下面我會將它們的繼承關系畫出來。
一些輔助方法
一些輔助方法可以生成特殊類型的Reader或者Writer:
funcLimitReader(r Reader, nint64) Reader
funcMultiReader(readers ...Reader) Reader
funcTeeReader(r Reader, w Writer) Reader
funcMultiWriter(writers ...Writer) Writer
繼承關系
當然,Go語言中并沒有Java中那樣的繼承關系,而是基于duck type形式實現,我用下圖嘗試展示Go io接口的繼承關系。

其中黃色是 bufio 包下的類型,
綠色是 archive.tar 包下的類型,
藍色是 bytes 包下的類型,
粉紅色是 strings 包下的類型,
紫色是 crypto.tls 包下的類型。
Rand 是 math.rand 包下的類型。
File 是 os 包下的內容。
`Rand`左邊的那個 Reader 是 image.jpeg 下的內容。
我們最常用的是包 io 、 bytes 、 bufio 下的類型,所以這幾個包下的類型要記牢,在第三庫中經常會出現它們的身影。
上圖中并沒有把 mime/multipart.File 和 net/http.File 列出來,主要是圖太復雜了,它們實現的接口和 os.File 類似。
當然你可能會問,你怎么整理的它們的繼承關系?事實上,你可以通過 godoc -analysis=type -http=:6060 生成帶繼承關系的Go doc,并且它還可以將你本地下載的庫中的繼承關系也顯示出來。

參考文檔
- https://golang.org/pkg/io/
- https://golang.org/pkg/bufio/
- https://golang.org/pkg/bytes/
- https://medium.com/@benbjohnson/go-walkthrough-io-package-8ac5e95a9fbd#.er7vmwvb3
- https://medium.com/@blumenmann/a-simple-beginners-tutorial-to-io-writer-in-golang-2a13bfefea02#.sm0gq7rn0
- https://www.reddit.com/r/golang/comments/4z2eo2/noob_question_how_to_discover_interface/
來自:http://colobu.com/2016/08/29/go-io-Reader-and-io-Writer/