go接口类型
go 接口定义了一组方法的签名(方法和函数的区别,参考go函数类型),它借鉴了 OOP 编程语言里 interface 的思想,但有一些不同。
1. 接口定义
go 里接口定义的语法如下:
type interface_name interface {
//method
}
为了方便理解接口,以生活中的例子来说明:生活中常见的动物一般会跑会叫,可以定义一个动物接口,包含跑和叫两个方法签名。注意到,interface
里面的 method 并没有func
关键字。
type Animal interface {
run()
bark()
}
接口可以用来声明变量,未初始化的接口类型变量值为nil
,类型也为nil
。
var animal Animal
fmt.Println("value of animal", animal)
fmt.Printf("type of animal %T", animal)
2. 实现接口
go 没有提供 implements 这样的关键字来实现接口。只要某种类型包含了接口里定义的所有方法,即该类型实现了接口。下面例子定义了Dog
和Cat
两种类型,并且都实现了run
和bark
方法,这样Dog
和Cat
都实现了Animal
接口,那么 go 允许将Dog
和Cat
赋值给Animal
。使用Animal
调用bark()
和run()
方法时,实际上调用的是Dog
或者Cat
对应的方法,即实现了多态。
package main
import "fmt"
type Animal interface {
run()
bark()
}
type Dog struct {
name string
}
type Cat struct {
name string
}
func (cat *Cat) run() {
fmt.Println(cat.name + " likes run")
}
func (cat *Cat) bark() {
fmt.Println(cat.name + " likes bark")
}
func (dog *Dog) run() {
fmt.Println(dog.name + " is runing")
}
func (dog *Dog) bark() {
fmt.Println(dog.name + " is barking")
}
func main() {
var animal Animal = &Dog{
name: "my dog",
}
animal.bark()
animal.run()
animal = &Cat{
name: "mimi",
}
animal.bark()
animal.run()
}
3. 空接口
如果一个接口没有定义任何方法,这个接口被称为空接口,空接口用interface{}
表示。所有的类型都实现了空接口,例如:
package main
import "fmt"
func emptyInterface(i interface{}) {
fmt.Printf("\ntype of parameter is %T", i)
}
func main() {
emptyInterface(10)
emptyInterface("abc")
emptyInterface(10.5)
emptyInterface(struct{ string }{"hhh"})
}
4. 类型断言和类型转换
前面例子中,Dog
和Cat
都可以赋值给Animal
这个接口,对于一个Animal
类型的变量,实际的类型是Dog
还是Cat
呢?这个时候可以使用类型断言。下面例子里,假定i
为T
类型,并将T
类型的值赋给变量t
,如果i
的实际类型不为T
(即断言失败),则会抛出异常。
t := i.(T)
类型转换提供了更加便捷的类型断言,它的语法和switch
类似。
switch v := i.(type) {
case T:
// here v has type T
case S:
// here v has type S
default:
// no match; here v has the same type as i
}