什么是接口
在Go语言中接口(interface)是一种类型,一种抽象的类型。
interface
是一组method
的集合,是duck-type programming
的一种体现。接口做的事情就像是定义一个协议(规则),只要一台机器有洗衣服和甩干的功能,我就称它为洗衣机。不关心属性(数据),只关心行为(方法)。为了保护你的Go语言职业生涯,请牢记接口(interface)是一种类型。
type Cat struct{}
func (c Cat) Say() string { return "喵喵喵" }
type Dog struct{}
func (d Dog) Say() string { return "汪汪汪" }
func main() {
c := Cat{}
fmt.Println("猫:", c.Say())
d := Dog{}
fmt.Println("狗:", d.Say())
}
上面的代码中定义了猫和狗,然后它们都会叫,你会发现main函数中明显有重复的代码,如果我们后续再加上猪、青蛙等动物的话,我们的代码还会一直重复下去。那我们能不能把它们当成“能叫的动物”来处理呢?
像类似的例子在我们编程过程中会经常遇到:
比如一个网上商城可能使用支付宝、微信、银联等方式去在线支付,我们能不能把它们当成“支付方式”来处理呢?
比如三角形,四边形,圆形都能计算周长和面积,我们能不能把它们当成“图形”来处理呢?
比如销售、行政、程序员都能计算月薪,我们能不能把他们当成“员工”来处理呢?
Go语言中为了解决类似上面的问题,就设计了接口这个概念。接口区别于我们之前所有的具体类型,接口是一种抽象的类型。当你看到一个接口类型的值时,你不知道它是什么,唯一知道的是通过它的方法能做什么。
实现
一个对象只要全部实现了接口中的方法,那么就实现了这个接口。换句话说,接口就是一个需要实现的方法列表。
// Sayer 接口
type Sayer interface {
say()
}
type dog struct {}
type cat struct {}
// dog实现了Sayer接口
func (d dog) say() {
fmt.Println("汪汪汪")
}
// cat实现了Sayer接口
func (c cat) say() {
fmt.Println("喵喵喵")
}
接口的实现就是这么简单,只要实现了接口中的所有方法,就实现了这个接口。
那实现了接口有什么用呢?
接口类型变量能够存储所有实现了该接口的实例。 例如上面的示例中,Sayer
类型的变量能够存储dog
和cat
类型的变量。
func main() {
var x Sayer // 声明一个Sayer类型的变量x
a := cat{} // 实例化一个cat
b := dog{} // 实例化一个dog
x = a // 可以把cat实例直接赋值给x
x.say() // 喵喵喵
x = b // 可以把dog实例直接赋值给x
x.say() // 汪汪汪
}
Error
除却空接口
interface{}
外,这应该是我们最常用到的接口了,众所周知Go没有抛出和处理异常的机制,所以我们经常就有看到Error的地方。
// The error built-in interface type is the conventional interface for
// representing an error condition, with the nil value representing no error.
type error interface {
Error() string
}
从Go的源码我们可以看出,只要你实现了Error() string
,你对应的类型就实现了error接口。
下面我们来正经的实验一下,首先建立一个结构体,然后实现Error()string
方法。
type Human struct {
Err error
}
func (h *Human)Error() string {
return fmt.Sprintf("%v", h.Err)
}
然后我们给他实现一个方法。抛出Error,我们返回的类型是error,可以看到,我们如果实现了Error方法,那么该结构体也是属于此类型(PS: 接口是一种类型)。
func (h *Human)Say() error {
for i:=0;i<5;i++ {
if i == 3 {
//return fmt.Errorf("Salmon Error")
h.Err = fmt.Errorf("Salmon Error2")
return h
}
}
return nil
}
func main() {
var h Human
err := h.Say()
if err != nil {
fmt.Println(err)
}else {
fmt.Println("Not Error")
}
}
看上去是不是很熟悉,这正是接口的实现的一些好处。
- Post link: https://www.godhearing.cn/go-jie-kou-jie-xi/
- Copyright Notice: All articles in this blog are licensed under unless otherwise stated.