IO流与接口

110 阅读2分钟

接口的基本使用

any类型

在go没有泛型的时代interface被大家广泛的使用,其中类型断言是最为广泛的使用方式。

func main() {
	var x any
	x=16.2
	switch x.(type) {
	case int:
		fmt.Println("x is int")
	case float64:
		fmt.Println("x is float64")
	case string:
		fmt.Println("x is string")
	case float32:
		fmt.Println("x is float32")
	}
}

这是switch的一种基础用法,在类型断言当中会返回两个值一个。如果断言成功那么就返回原本的值和一个布尔值如果失败了布尔值就会为false,所以在使用类型断言就一定要先判断这个布尔值。
其中any已经可以在go当中直接使用,可以在源文件里面看到type any=interface{}这样就不用写繁琐的interface{}有时候初始化切片经常会看到interface{}{}十分的不优雅。

应用接口

在go语言当中是没有imp之类的关键字,要触发编译前类型检查就要使用下面这种方法。这个例子里面要实现http.Handler接口

type Handler struct {
	// ...
}

// 用于触发编译期的接口的合理性检查机制
// 如果 Handler 没有实现 http.Handler,会在编译期报错
var _ http.Handler = (*Handler)(nil)

func (h *Handler) ServeHTTP(
	w http.ResponseWriter,
	r *http.Request,
) {
	// ...
}

接口函数

在go的http标准库当中就使用了接口函数,在其他go语言框架当中也是广为应用。

type Route interface {
    Get(*server.Hertz)
}
type RouteFunc func(*server.Hertz)
func (f RouteFunc) Get(app *server.Hertz){
    f(app)
}

这样子注册一个路由既可以用结构体来注册也可以用函数,从而可以提升代码的可读性。不过我这样的用法不是特别的好,但是接口函数也有它的价值所在。

IO流与接口

IO是实际项目当中应用最为广泛的一种标准库,在青训营的课程当中的socket5代理就对IO进行了比较多的应用。在go语言当中继承是用的比较少的,最为广泛的就是组合。

统计字符个数

在go的各种IO操作都离不开这两个接口io.Readerio.Writer从函数原型上面来看io.Reader(p []byte) (n int, err error)就是从p这个切片写入数据然后返回大小和一个错误。如果文件读取完成那么就会返回一个io.EOF抽象性极强但是很实用。下面是一个简单的例子。

func ReadA(f *os.File) {
	// 关闭文件句柄
	defer f.Close()
	count := 0
	scanner := bufio.NewScanner(f)
	for scanner.Scan() {
		count+=strings.Count(scanner.Text(),"go")
		count+=strings.Count(scanner.Text(),"Go")
	}
	fmt.Println("文件中go的个数是", count)
}

这里统计了一个文件中go字符出现的次数。go当中有很多Reader但是来源基本上都是io.Reader之所以这样做是为了降低复杂性。

将http请求写入文件中

func hertz(f *os.File) {
	defer f.Close()
	h := server.Default()

	h.GET("/f", func(c context.Context, ctx *app.RequestContext) {
		_,err:=io.Copy(f, strings.NewReader(ctx.Request.Header.String()))
		if err != nil {
			panic(err.Error())
		}
		ctx.JSON(consts.StatusOK, utils.H{
			"msg": "success",
		})
	})

	h.Spin()
}

使用io.Copy可以轻松的将各种流写入文件,可以说是十分的方便。这样可以降低代码的复杂性提升可读性。