以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")

也就是标准输出.
从这里可以看出

  1. NewFile方法new出来的os.FileWrite方法,那么os.File这个Struct就已经实现了io.Writer接口
  2. 上面的=号说明了os.Stdout就是NewFile方法new出来的,他是os.File
  3. 结合前面的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方法)

抱歉,比较啰嗦,为了以后能看懂

本文来自:开源中国博客

感谢作者:waynehu

查看原文:以io.Writer为例看go中的interface{}

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。