接口
在 Go 语言中接口包含两种含义:它既是方法的集合, 同时还是一种类型。
在Go 语言中是隐式实现的,意思就是对于一个具体的类型,不需要声明它实现了哪些接口,只需要提供接口所必需的方法。
非空接口
例如:
type Person interface {
GetName() string
}
type user struct {
name string
}
func (u user) GetName() string {
return u.name
}
func main() {
var p Person
u := user{"zhangsan"}
p = u
fmt.Println(p.GetName())
}
上述代码声明了一个Person接口,Person接口有一个GetName的方法。
而user结构体实现了一个同样名字和参数,返回类型的方法。则说明user实现了该接口。所以可以把user类型的值赋值给该接口类型的变量。
此时该接口的静态类型为Person,动态类型为user,动态值为u
空接口
没有任何方法的接口为空接口,在 Go 语言里面可以认为所有类型实现了空接口。
例如:
type empty interface {
}
func main() {
var e empty
e = 1
fmt.Print(e)
}
空接口类型的变量可以赋予任何值,所有类型都可以安全的转换到空接口上。也正因此,空接口名正言顺的成为了GO实现多态的基础。
当一个函数的形参是空接口interface{},函数内部在使用的时候,需要显式的获得该空接口所持有数据的类型和所持有的数据,才能进行后续的运算。即需要从空接口断言,获得它的真实(动态)类型。
类型断言
是一个使用在接口值上的操作,用于检查接口类型变量所持有的值是否实现了期望的接口或者具体的类型。 断言的两种形式:
- 安全的断言方法:
<目标类型值>, ok := <空接口值>.(目标类型) - 非安全的断言方法:
<目标类型值> := <空接口值>.(目标类型)
安全的断言方法用的最多,即增加了bool类型的ok值,来捕获该次断言是否成功,从而避免断言失败造成panic进而引起程序的崩溃。
T为具体类型:检查a的动态类型是否与T类型相同,如果检查成功,类型断言返回的结果是a的动态值,其类型是T。
package main
import (
"fmt"
)
func main() {
var x interface{}
x = 10
value, ok := x.(int)
fmt.Print(value, ",", ok)
}
T为接口类型:可以用来检测a的动态类型是否实现了接口T,如果检查成功,返回值是一个类型为T的接口值。
type A interface {
GetName() string
}
type Person interface {
GetName() string
GetId() int32
}
type user struct {
name string
id int32
}
func (u user) GetName() string {
return u.name
}
func (u user) GetId() int32 {
return u.id
}
func main() {
var p Person
u := user{"zhangsan", 1}
p = u
v, ok := p.(A)
fmt.Printf("%T\n", v) //main.user
fmt.Println(ok) //true
}
接口类型变量p实现了A接口,所以类型断言成功。
无论 T 是什么类型,如果 a 是 nil 接口值,类型断言都会失败
Type Switch
用来判断某个 interface 变量中实际存储的变量类型。
Type Switch 语法格式如下:
switch x.(type){
case type:
statement(s);
case type:
statement(s);
/* 你可以定义任意个数的case */
default: /* 可选 */
statement(s);
}