2022年8月

接口

基础类型 -> struct

type cat struct {...}
type dog struct {...}
func (c cat) eat() {...}
func (d doy) eat() {...}
// 该函数其实是想,传入什么,我就撸什么。如果x的类型是cat,将来只能传递cat类型的变量
// 那dog类型的怎么办?该函数无法支持。struct解决不了这类问题
func lu(x cat) {...}
lu(cat)
lu(dog)  // 无法传入dog类型

struct -> interface

// 引入接口
type eater interface {
    eat()
}
func lu(x eater) {...}
lu(cat)
lu(dog)

接口就是一个特殊类型。它规定了有哪些方法。一个变量实现了接口内的所有方法,就是这个特殊类型的变量。

var d dog
var e eater
// d实例实现了eater的eat(),那么d就是这个接口类型的变量
// 此时d既是struct类型,又是interface类型
e = d

接口变量保存以下 2 个部分:

  • 动态类型:零值nil
  • 动态值:零值nil
fmt.Printf("%T, %v\n", e, e)

这样就能实现接口变量的动态性。可以理解,接口就是一个动态变量。

函数参数:接口

相当于给函数传入实例对象的方法集,能实现方法集内的方法的实例对象,都能执行该函数。

实现接口时:值接收者 VS 指针接收者

  • 值接收者:结构体类型、结构体指针类型的变量都支持
  • 指针接收者:仅支持结构体指针类型的变量

接口嵌套

type sleeper interface {
    sleep()
}
type eater interface {
    eat()
}
type animal interface {
    sleeper
    eater
}

空接口

没有方法,所有类型都实现可以实现空接口。因此 interface{} 通常用来表示任意类型。

// 接口作参数
func show(a interface{}) {
    fmt.Printf("%T, %v", a, a)
}
// 还不知道存入的值是什么类型时
var m = make(map[string]interface{}, 8)

如何判断接口这个动态变量的类型

  • 类型断言
  • 反射

类型断言

x.(type)
// x:    类型为 interface{} 的变量
// type: 断言这个x变量可能的类型
// 返回2个值 v, ok
// 如果ok=true,那么v的类型就是type;如果ok=false,那么v的类型就不是type
func guessType(a interface{}) {
    if s, ok := a.(string); ok {
        fmt.Printf("is a string, value is %v\n", s)
    } else {
        fmt.Printf("unknown type\n")
    }
}
func guessType(a interface{}) {
    switch v := a.(type) {
    case string:
        fmt.Printf("is a string, value is %v\n", v)
    case int:
        fmt.Printf("is a int, value is %v\n", v)    
    case bool:
        fmt.Printf("is a bool, value is %v\n", v)
    default:
        fmt.Printf("unknown type\n")
    }
}

反射

等待学习反射