理解interface
接口
基础类型 -> 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")
}
}
反射
等待学习反射