阅读该文后的一些理解
###1 io.Writer接口 io.Writer接口有如下定义
package io
type Writer interface {
Write(p []byte) (n int, err error)
}
//根据go中接口的特点,所有实现了Write方法的类型,我们都说它实现了io.Writer接口。
###2 somepkg.abc类型实现了io.Writer接口
package somepkg
type Abc struct {
id int
}
func (a *Abc) Write(p []byte) (n int, err error){
//writing....
return 1,nil //模拟返回,n表示写了几个字节,err表示是否有错误
}
//根据go中接口的特点,由于abc类型实现了Write方法,我们就说abc类型实现了io.Writer接口。
###3 io.Writer的应用 通常,我们在使用fmt包的时候是使用Println/Printf/Print方法。其实,在fmt包中还有Fprint序列方法,而且,Print序列方法内部调用的是Fprint序列方法。以Fprintln为例看看方法的定义:
func Fprintln(w io.Writer, a ...interface{}) (n int, err error)
方法的第一个参数是io.Writer,也就是说,任何实现了io.Writer接口的类型实例都可以传递进来;
我们再看看Println方法内部实现:
func Println(a ...interface{}) (n int, err error) {
return Fprintln(os.Stdout, a...)
}
我们不妨追溯一下os.Stdout:
Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout")
也就是标准输出.
从这里可以看出
- NewFile方法new出来的os.File有Write方法,那么os.File这个Struct就已经实现了io.Writer接口
- 上面的=号说明了os.Stdout就是NewFile方法new出来的,他是os.File
- 结合前面的1和2,如果某个方法需要一个io.Writer接口作为参数传入的话,完全可以拿os.Stdout作为一个io.Writer接口来用
再看一遍Fprintln方法的定义:
func Fprintln(w io.Writer, a ...interface{}) (n int, err error)
如果第一个参数传递的是一个os.Stdout,内容便会被输出到标准输出,也就是屏幕上。
如果第一个参数传递的是一个普通文件,内容便会被输出到该文件。
如果第一个参数传递的是bytes.Buffer,那么,内容便输出到了buffer中。
###4 与上面的somepkg结合
package main
import "somepkg"
import "fmt"
func main(){
a := &somepkg.abc{1}
i,e :=fmt.Fprintln(a,"hello world")
fmt.Println(i) // 1
}
"hello world"会写入到a里,具体是如何写的,调用的是abc里的Write方法 当然目前示例abc里的Write方法根本就没有还没写,只是返回了1和nil,所以后面的1会被打印出来
###5 最后 接口命名一般以“动作+er”,理解为可以怎么怎么样的“人”,比如Writer为可以理解为“会Write的人”
一旦某人(某个Struct)有能力Write了(实现Write方法了),我们就自动的认为他是个“会写的人”,是个Writer
任何实现Write方法的Struct都可以当做io.Writer来传递给相关方法(如Fprintln方法)
抱歉,比较啰嗦,为了以后能看懂