接口即约定,通过interface关键字定义了接口以后,凡是满足定义的都被认定为该接口的实现。这是隐式实现方式,与Java通过implements
关键字显式实现是完全不同的。
定义了一个接口,且存在某个类型完全满足这个接口的定义,那么这个类型就实现了这个接口,不需要单独使用某个关键字去说明。
在GO语言中这种接口隐式实现方式允许在具体类型已经存在的情况下再去定义接口可以先有类型再有接口,不会破坏原有定义。
一、接口使用
接口定义了需要被实现的一组函数方法的抽象集合,如果需要实现某个接口就必须实现该接口的所有方法。
这里的类型retangle
和 类型circle
实现了接口ShapeDesc
,我们可以使用接口变量来接收类型的变量。
func main() {
var s1,s2 ShapeDesc
s1 = rectangle{H:2,W:3} //注意此处,rectangle实现了ShapeDesc接口
s2 = circle{R:2} //注意此处,circle实现了ShapeDesc接口
Desc(s1)
Desc(s2)
}
func Desc(s ShapeDesc) {
switch kind := s.(type) {
case circle:
fmt.Println("This is circle.")
case rectangle:
fmt.Println("This is rectangle.")
default:
fmt.Println("%v is unknown type",kind)
}
fmt.Println("area:",s.Area())
fmt.Println("perimeter:",s.Perimeter())
}
上面我们说过了,类型实现了接口,我们可以使用接口变量来存储类型的变量,但是此时的变量只能调用接口所定义的方法,而接口中的方法是未实现的,此时就需要通过断言转换变量类型后再去调用。
Go语言中的类型断言。因为接口的值是动态的,需要判断其具体类型是什么、接口类型是什么,这种操作就是类型断言。
Go语言的类型断言可以用x. (T)表达,其中x是一个接口类型的具体值表达
式,而T是一个类型一断言类型。T的主要作用就是检查动态值x是否满足T。
kind := s.(type)
接口类型的值存储包含两个部分:一个具体类型和该类型的一个值,分别称为动态类型和动态值。我们在编译阶段并不知道具体的类型和值,而是在程序执行到此时再通过动态类型和动态值去调用具体方法。
- 接口中只能声明方法,不可以有具体实现。
- 接口中不可以声明变量,仅允许声明方法。
- 实现一个接口,就必须实现接口内声明的所有方法。
- 实现一个方法就是要和接口声明的方法的方法名、形参、返回值完全一致。
二、空接口
使用interface{}
定义接收任何类型的接口。空接口类似于其他面向对象语言的Object。
Go语言的面向对象依赖于接口,而不是依赖于实现。