在一个基于缓冲和非缓冲输出的代码测试过程中, 一些接口类型使用时的思考过程(超详细)
```
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
// io包中接口的概念
fmt.Fprintf(os.Stdout, "%s\n", "这些文字不经过缓冲")
// 通过bufio标准库创建一个io.Writer接口类型变量的缓冲
/**
* bufio中的Writer类型(结构体) 实现了io.Writer接口对象提供的缓冲.
* 如果在向一个Writer类型值写入时遇到了错误, 该对象不再接受任何数据,且所有写操作都会返回该错误
* 再说数据都写入后, 调用者有义务调用Flush方法以保证所有的数据都交给了下层的io.Writer
*
* bufio.NewWriter() 返回了一个bufio.Writer的指针
* 调用逻辑:
* bufio.NewWriter 需要传入一个实现io.Writer接口的变量
* 此时传入的值是 os.Stdout
* >os.Stdout是什么 它是os.File的指针, 溯源代码可以发现os.Stdout 的文件描述符是1 即输出他的变量构建通过os中的NewFile创建了一个&File
* >那此时我们想到传参其实是需要是实现io.Writer类型的变量, os.File是否实现了io.Writer 我们看一看
* >回想go的接口实现, 当一个变量被要求是指定接口类型时, 此变量类型上一定定义了接口中要求的方法, 此例中, io.Writer要求实现了Write方法签名, io.Write方法参数要求一个byte切片类型并返回一个整型和错误
* >回到第一步分析, os.Stdout是一个os.File的指针, 那么os.File类型的指针变量是否实现了io.Writer接口?(是的, 移步查看os中结构体File上定义的方法, 这里对于面向对象转来的同学不好理解, 接口在哪里实现)
* >针对上一行问题引入io标准库和os标准库的概念:
* >io库提供了对I/O原语的基本接口, 可以理解为将这些原语的现有实现(如os库中的原语) 包装到抽象功能的公共接口中, 以及一些其他的相关原语
* >os库为操作系统功能提供了一个独立于平台的接口. 设计类似于Unix, 进款错误处理类似于Go; 失败的调用返回错误类型的值,而不是错误号.os接口旨在在所有操作系统中保持统一的接口形态.通常不可用的功能出现在系统特定的包系统调用中
* > OK, 了解完以上两个概念以后, 我们并没有看到问题得到解释
* > 那我们只能回到代码寻找一些证据, 那么我们可以找到io库中的Writer是一个接口,此接口要求变量是一个实现了Write方法的类型
* > os.File类型上定义了Write方法此方法的签名结构和io.Writer要求的结构一致, 回想我们对Go语言接口实现的认知, Go语言的接口是被隐式实现的, 即只要实现了接口中的方法就实现了改接口
* > 综上, 解释了为什么os.Stdout 是 io.Writer 接口类型 (有时候直观上看不到继承, 尤其是从面向对象来的同学可能会很诧异这个类型是怎么被实现的, 这里就完美的做一个思维上的理解)
*/
buf := bufio.NewWriter(os.Stdout)
fmt.Fprintf(buf, "%s\n", "这些文字在缓冲区中")
// 此时如果不调用buf.Flush 则所有数据仍然在缓冲中, 并未将数据刷给下层的io.Writer
buf.Flush() // Flush方法将缓冲区中的数据写入下层的io.Writer接口
}
```
有疑问加站长微信联系(非本文作者))