接口类型是对其它类型行为的抽象和概括,我的理解是,可以更方便的处理不同类型数据。在 js 里没有特别的明确数据类型,比如 1 + '2'
是 '12'
而 1 - '2'
是 -1
,在 go 里这样的语句是错误的。
接口的概念非常多,小章节是之前每个章节的2,3倍。
接口约定
由于 go 是强类型的静态语言,例如一个函数定义时声明了类型,则只能处理该类数据。
如果仅仅是数据类型不同,处理方式一模一样的情况,难道要重写一份吗?肯定不是这样的。
接口类型,将改变这一切。
最简单的例子,如 fmt.Printf
可以接受任何类型的数据。
1 | package fmt |
虽然一开始我没看懂,但是看完后才发现原来如此简单。
参数部分是 args ...interface{}
,是一个空接口,可以理解为接收任意类型的参数。
其中 io.Writer
是‘可写’接口:
1 | package io |
这么看感觉只是把函数声明写到这里而已,确实是这样的,把函数声明写一遍即可。
这个接口的意思为:某个类型只要有 Write
方法,就可以接收。
1 | type ByteCounter int |
比如这个 int
的别名 ByteCounter
类型,定义了一个 Write
方法。
1 | var c ByteCounter |
他就可以当做第一个参数被调用,而且正确执行了 Write
方法。
第一小节花的时间略多,因为概念基本在这了,后面只是延伸和应用。
接口类型
接口类型其实跟结构体类似,只是关键词不一样,因为接口也可以像结构体一样声明跟嵌入,这里就不多解释了。
实现接口的条件
一个类型如果拥有一个接口需要的所有方法,那么这个类型就实现了这个接口。
简单说,如果一个接口有 a,b 方法,你的类型必须也有 a,b 方法才能满足这个接口类型,否则无法被赋值或当参数接收。
但如果你的类型有 a,b,c,d 甚至更多方法,那么你的类型也满足了这个接口。
简单说就是只能多不能少,只有被满足的才能被赋值或当参数接收,当然空接口除外,任何数据都满足空接口。
flag.Value 接口
粗略看了,貌似处理命令行输入的,通过 flag.Value
接口,自定义处理控制台输入。
1 | type Value interface { |
接口值
概念上讲一个接口的值,接口值,由两个部分组成,一个具体的类型和那个类型的值。
1 | var w io.Writer |
这货说难也难,说简单也简单。
sort.Interface 接口
排序接口,可以对任意数据类型进行排序,只要简单实现3个接口即可。
1 | package sort |
例子就略了。。
http.Handler 接口
略,等学 web 的时候细学。
error 接口
简单粗暴:
1 | type error interface { |
创建一个error最简单的方法就是调用errors.New函数,它会根据传入的错误信息返回一个新的error。
整个errors包仅只有4行:
1 | package errors |
两个 error 是不相等的。
1 | fmt.Println(errors.New("EOF") == errors.New("EOF")) // "false" |
类型断言
使用 x.(T)
语法对 x 进行 T 类型的断言。
1 | var w io.Writer |
当类型断言的操作对象是一个变量,你有时会看见原来的变量名重用而不是声明一个新的本地变量,这个重用的变量会覆盖原来的值,如下面这样:
1 | if w, ok := w.(*os.File); ok { |
小结
后续几个小章结都是应用,等实际应用时踩坑了,光这样死记硬背也没用。