接口
接口(interface)定义了一个对象的行为规范,只定义规范不实现,由具体的对象来实现规范的细节
//定义一个接口
type Car interface {
run()
}
type paoceh struct {
name string
}
//实现该接口的方法
func (s paoceh)run() {
fmt.Printf("%s正在跑路",s.name)
}
// Drive 调用该接口里面的run方法
func Drive(c Car) {
c.run()
}
func main() {
p := paoceh{
name: "奔驰",
}
Drive(p)
}
值接收者实现接口与指针接收者实现接口
//传入指针
func Drive2(c *paoceh) {
fmt.Println("指针的操作")
}
func main() {
p := &paoceh{
name: "奔驰",
}
Drive(p)//奔驰正在跑路
c := paoceh{
name: "奔驰",
}
Drive(c)//奔驰正在跑路
//上述结果表明传地址与值效果一样
var cc *paoceh
cc = &c
Drive2(cc)//指针的操作
}
区别:对于值接收者实现的接口,无论使用值类型还是指针类型都没有问题。但是我们并不总是能对一个值求址,所以对于指针接收者实现的接口要额外注意。
空接口的应用
使用空接口实现可以接收任意类型的函数参数。
// 空接口作为函数参数
func show(a interface{}) {
fmt.Printf("type:%T value:%v\n", a, a)
}
空接口作为map的值
var studentInfo = make(map[string]interface{})
studentInfo["name"] = "沙河娜扎"
studentInfo["age"] = 18
studentInfo["married"] = false
fmt.Println(studentInfo)
类型断言
想要从接口值中获取到对应的实际值需要使用类型断言,其语法格式如下。
x.(T)
x:表示接口类型的变量
T:表示断言x可能是的类型
/ justifyType 对传入的空接口类型变量x进行类型断言
func justifyType(x interface{}) {
switch v := x.(type) {
case string:
fmt.Printf("x is a string,value is %v\n", v)
case int:
fmt.Printf("x is a int is %v\n", v)
case bool:
fmt.Printf("x is a bool is %v\n", v)
default:
fmt.Println("unsupport type!")
}
}
由于接口类型变量能够动态存储不同类型值的特点,所以很多初学者会滥用接口类型(特别是空接口)来实现编码过程中的便捷。只有当有两个或两个以上的具体类型必须以相同的方式进行处理时才需要定义接口。切记不要为了使用接口类型而增加不必要的抽象,导致不必要的运行时损耗。
在 Go 语言中接口是一个非常重要的概念和特性,使用接口类型能够实现代码的抽象和解耦,也可以隐藏某个功能的内部实现,但是缺点就是在查看源码的时候,不太方便查找到具体实现接口的类型。