接口(interface)是一种类型,一种抽象类型。它是一组方法的签名,是一组仅包含方法名、参数、返回值的未具体实现的方法的集合。当不同的父类具有相同的行为的时候,单一继承无法解决,所以接口是来解决多个类型实现一个接口(“多态”)。接口是duck-type programming(鸭子形)的一种体现。
二.接口的格式在java,php等语言,实现接口使用关键字:implements,而在Golang中接口是隐式地实现。
type 接口类型名 interface{
方法名1( 参数列表1 ) 返回值列表1
方法名2( 参数列表2 ) 返回值列表2
…
}
-
接口名:使用type将接口定义为自定义的类型名。Go语言的接口在命名时,一般会在单词后面添加er,如有写操作的接口叫Writer,有字符串功能的接口叫Stringer等。接口名最好要能突出该接口的类型含义。
-
方法名:当方法名首字母是大写且这个接口类型名首字母也是大写时,这个方法可以被接口所在的包(package)之外的代码访问。
-
参数列表、返回值列表:参数列表和返回值列表中的参数变量名可以省略。
定义一个 Sayer 接口
type Sayer interface {
say()
}
定义dog和cat两个结构体
type dog struct {
name string
}
type cat struct {
name string
}
实现接口方法
// 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() // 汪汪汪
}
五.接口嵌套
接口与接口间可以通过嵌套创造出新的接口。
// Sayer 接口
type Sayer interface {
say()
}
// Mover 接口
type Mover interface {
move()
}
// 接口嵌套
type animal interface {
Sayer
Mover
}
animal接口类型变量可以直接调用嵌套的接口Sayer, Mover方法(和结构体嵌套类似)
六.空接口空接口就是不包含任何方法的接口。正因为如此,所有的类型都实现了空接口
1.空接口存储任意类型的值
// 定义a为空接口
var Any interface{}
var i int = 5
var s string = "Hello world"
// cbs可以存储任意类型的数值
cbs = i
cbs = s
2.空接口作为函数的参数
使用空接口实现可以接收任意类型的函数参数。比如fmt.Printf就使用空接口作为参数接受任意类型的值。
// 空接口作为函数参数 可以传入任何类型的值
func show(a interface{}) {
fmt.Printf("type:%T value:%v\n", a, a)
}
3.空接口作为map的值
// 空接口作为map值
var studentInfo = make(map[string]interface{})
studentInfo["name"] = "字符串"
studentInfo["age"] = 18
studentInfo["work"] = false
fmt.Println(studentInfo)
4.空接口作为slice的值
// 空接口作为slice值
var anyslice =make([]interface{},3,3)
studentInfo[0] = "字符串"
studentInfo[1] = 18
studentInfo[2] = false
fmt.Println(anyslice )
因为空接口可以存储任意类型值的特点,所以空接口在Go语言中的使用十分广泛。
七.注意关于接口需要注意的是,只有当有两个或两个以上的具体类型必须以相同的方式进行处理时才需要定义接口。不要为了接口而写接口,那样只会增加不必要的抽象,导致不必要的运行时损耗。