Go语言中的接口
接口是一组方法的集合,定义了接口中存储的数据实例的行为
任何数据实例只要全部实现了这些方法就是实现了这个接口
既然接口定义了数据实例的行为,就意味着接口必须赋值一个数据实例,然后这个数据实例才能使用接口中的方法
每一个接口都包含两个属性,一个是值,一个是类型
定义接口
type interface_name interface { method_name1 [return_type] method_name2 [return_type] ... method_namen [return_type] }以下为一个实现接口的实例
type Human interface { eat(food string) string sleep() } //定义一个human接口 type People struct { name string } //定义一个结构体 func (who People) eat(food string) string { fmt.Println(me.name,"吃",food) return "吃饱了" } func (who People) sleep() { fmt.Println(me.name,"睡觉") } //实现接口所有方法并绑定到People结构体的who实例变量上 func main() { var me Human //声明一个要实现接口的变量 me = People {name:"三千"} //给接口赋值,让值绑定接口 //上面两句可以直接使用一句 //var me Human = People {name:"三千"} fmt.Println(me.eat("面条")) me.sleep() } 上面程序运行后会显示: 三千 吃 面条 吃饱了 三千 睡觉
空接口
空接口是特殊形式的接口类型,普通的接口都有方法,而空接口没有定义任何方法
可以说所有类型都至少实现了空接口,也就是说空接口可以承载任意类型的值
一个空接口的值和类型都是nil
使用空接口
直接使用 interface{} 作为类型声明一个承载任意类型值的变量
var demo interface{} demo = 5 demo = "hello" demo = true 一个空接口可以赋予任何类型的值 使用func demo (faces ...interface{})可以接受任意个任意类型的值
当空接口承载数组或切片后,该对象无法进行切片(arr[start_index:end_index])操作
断言类型(Type Assertion)
当使用空接口来接收任意类型的值时,它的静态类型是 interface{},但动态类型我们并不知道,因此需要使用类型断言(Type Assertion)来判断其动态类型,即其承载的数据的数据类型
类型断言仅能对静态类型为空接口(interface{})的对象进行,否则会抛出错误
断言类型的格式:val.(type_name)
会返回两个值,第一个是变量所存储的实际数据,第二个是断言类型的结果(bool值)
首先判断变量的值是否非nil 然后判断变量的值是否是type_name类型 两个条件都通过会返回变量的值和true 有一个条件不通过会返回type_name的默认值和false
当断言类型失败时,如果有变量接收第二个返回值(false)则正常运行,如果没有变量接受会触发panic
var demo interface{} = "hello" var a = demo.(string) var b,ok = demo.(int) var c = demo.(int) 变量a由于断言成功被赋值"hello" 变量b断言失败但是有ok变量接受false,所以会被赋值int默认值0 变量c初始化时由于断言失败而没有接收第二个返回值,触发panic
如果需要断言多种类型,使用type-switch流程控制语句比一个个进行类型断言更简单、直接、高效
var demo = interface{}("demo") switch v := demo.(type){ case int: fmt.Println("demo的类型是int") case string: fmt.Println("demo的类型是string") case nil: fmt.Println("demo的类型是空值nil") default: fmt.Printf("demo为未知类型") }
静态类型和动态类型
静态类型(static type)
就是声明变量时的类型,是编码代码时就确定的
var age int // 静态类型int var name string // 静态类型string var demo interface{} // 静态类型interface{}
动态类型(concrete type)
也叫具体类型,是程序运行时系统才能看见的类型,是由空接口实现的
var demo interface{} demo = 5 demo = "hello"
以上代码中在声明变量demo时指定了变量为interface{}类型,所以demo的静态类型就是interface{},这个是在编写代码的时候就确定且不会改变的。
后面我们又给demo变量赋值int类型5,此时它的静态类型还是interface{},这是不会变的,但是它的动态类型此时变成了int类型
同理,我们给变量赋值string类型"hello",此时它的静态类型还是interface{},它的动态类型此时又变成了string类型
无论是demo=5还是demo="hello",都是当程序运行到这里时,变量的类型,才发生了改变,也就是程序运行时才能确定的类型
由于动态类型的存在,在一个函数中接收的参数的类型有可能无法预先知晓,此时我们就要对参数进行反射,然后根据不同的类型做不同的处理