以io.Writer为例看go中的interface{}
阅读该文后的一些理解
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方法)
抱歉,比较啰嗦,为了以后能看懂
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。