概述

interface 是一个定义了方法签名的集合,用来指定对象的行为,如果对象做到了Interfac中方法集定义的行为,那就可以说实现了Interface。

声明

接口的声明使用 interface 关键字 。
接口按照约定只包含一个方法的,接口的名字由方法名加 [e]r 后缀组成,例如 Printer、Reader、Writer、Logger、Converter 等等。还有一些不常用的方式(当后缀 er 不合适时),比如 Recoverable,此时接口名以 able 结尾,或者以 I 开头(像 .NET 或 Java 中那样)。

  1. 只要某个类型拥有该接口的所有方法签名,即算实现该接口,无需显示声明实现了哪个接口。
  2. 接口只有方法声明,没有实现,没有数据字段。
  3. 接口可以匿名嵌入其他接口,或嵌入结构中。
  1. /* define an interface */
  2. type interface_name interface {
  3. method_name1 [return_type]
  4. method_name2 [return_type]
  5. method_name3 [return_type]
  6. ...
  7. method_namen [return_type]
  8. }
  9. /* define a struct */
  10. type struct_name struct {
  11. /* variables */
  12. }
  13. /* implement interface methods*/
  14. func (struct_name_variable struct_name) method_name1() [return_type] {
  15. /* method implementation */
  16. }
  17. ...
  18. func (struct_name_variable struct_name) method_namen() [return_type] {
  19. /* method implementation */
  20. }

空接口

没有任何方法的接口,我们称之为空接口。所以任何类型都实现了空接口,空接口表示为:

  1. interface {
  2. }

空接口用途
1 GO语言没有泛型,如果一个函数需要接收任意类型的参数, 则参数类型可以使用空接口类型,这是弥补没有泛型的一种手段。
空接口和反射
空接口是反射实现的基础 ,反射库就是将相关具体的类型转换并赋值给空接口后才去处理。
空接口和nil
空接口有两个字段, 一个是实例类型,另 一个是指向绑定实例的指针,只有两个都为nil时 ,空接口才为nil。

指针接收和值接收

TypeAssertion

判断接口变量的的具体类型,需要使用到类型断言type assertion。它的语法是:

  1. 变量名称.(数据类型)

判断当前的a的数据类型是字符串,如果当前a不是字符串使用下面写法会引起panic

  1. func printStr(a interface{}){
  2. fmt.Println(a.(string))
  3. }
  4. func main() {
  5. a := 10
  6. printStr(a)
  7. }

为了避免 panic 错误发生,可以通过如下操作来进行断言检查,断言会返回一个bool类型的参数 告诉是否断言的类型是否真的匹配

  1. t, ok := i.(T)

断言成功,ok 的值为 true,断言失败 t 值为T类型的默认值,也不会引起panic。如下

  1. func printStr(a interface{}){
  2. if v, ok := a.(string); ok {
  3. fmt.Println(v)
  4. }else {
  5. fmt.Println("不是字符 无法打印")
  6. }
  7. }
  8. func main() {
  9. a := 10
  10. printStr(a)
  11. printStr("test")
  12. }

TypeSwitch

另外一种判断interface变量的具体类型,那就是利用 switch 语句。

  1. func printValue(v interface{}) {
  2. switch v := v.(type) {
  3. case string:
  4. fmt.Printf("%v is a string\n", v)
  5. case int:
  6. fmt.Printf("%v is an int\n", v)
  7. default:
  8. fmt.Printf("The type of v is unknown\n")
  9. }
  10. }
  11. func main() {
  12. v := 10
  13. printValue(v)
  14. s := "test"
  15. printValue(s)
  16. }

编译期间判断是否实现了某个接口

  1. var _ Pooler = new(WeightedRoundRobin)

Pooler是一个接口类型。

  1. type Pooler interface {
  2. // ...
  3. }

如果说次接口没有被实现,ide会有红横线出现,另一方面在编译的时候会出现报错。两方面的提示来保证写底层代码的接口是有被实现的。

接口类型&nil

  1. package main
  2. import "fmt"
  3. type Foo interface {
  4. bar()
  5. }
  6. type FooType struct {
  7. }
  8. func (f FooType)bar(){
  9. fmt.Println("hello world")
  10. }
  11. func main() {
  12. var f Foo
  13. fmt.Println(f==nil)
  14. fmt.Printf("%T %v\n",f,f)
  15. var t *FooType
  16. fmt.Println(t==nil)
  17. fmt.Printf("%T %v\n",t,t)
  18. f = t
  19. fmt.Println(f==nil)
  20. fmt.Printf("%T %v\n",f,f)
  21. }

打印结果

  1. true
  2. <nil> <nil>
  3. true
  4. *main.FooType <nil>
  5. false
  6. *main.FooType <nil>

自动检测类型是否实现接口

  1. package main
  2. type Foo interface {
  3. bar()
  4. }
  5. type FooType struct {
  6. }
  7. //func (f FooType)bar(){
  8. // fmt.Println("hello world")
  9. //}
  10. func main() {
  11. var _ Foo = (*FooType)(nil)
  12. }

参考

https://blog.csdn.net/tomatomas/article/details/95880842
https://blog.keyboardman.me/2018/05/12/nil-in-go/
https://www.jianshu.com/p/dd80f6be7969