接口
在 Go 语言中,接口是一组仅包含方法名、参数、返回值的未具体实现的方法的集合。
scss
type Animal interface {
Sing()
GetName() string
}
在 Go 语言中,类对接口的实现和子类对父类的继承一样,并没有提供类似 implement
这种关键字显式声明该类实现了哪个接口,一个类只要实现了某个接口要求的所有方法,我们就说这个类实现了该接口。
go
type Chicken struct {
Name string
}
func (ch *Chicken) Sing() {
fmt.Println(ch.Name + "在打鸣")
}
func (ch *Chicken) GetName() string {
return ch.Name
}
Chicken
结构体实现Animal
接口声明的所有方法,则Chicken
结构体就实现了Animal
接口。
通过组合实现接口继承
Go 语言也支持类似的「接口继承」特性,但是由于不支持 extends
关键字,是通过组合来完成的。
go
type Animal interface {
Call()
}
type Bird interface {
A
Fly()
}
type Chicken struct {}
func (c Chicken) Call() {
fmt.Println("小鸡在打鸣")
}
func (c Chicken) Fly() {
fmt.Println("小鸡会飞")
}
Chicken
结构体可以只实现 Call
方法,也可以只实现 Fly
方法,也可以都不实现。如果只实现了 Call
方法,则 Chicken
实现了接口 Animal
;如果只实现了 Fly
方法,则既没有实现接口 Animal
也没有实现接口 Bird
,只有两个方法都实现了系统才会判定实现了接口 Bird
。
接口断言
Go 语言通过类型断言运算符 .(type)
来实现,其中 type
对应的就是要断言的类型。下面,我们来看下具体的使用示例。
go
type Animal interface {
Sing()
GetName() string
}
type Chicken struct {
Name string
}
func (ch *Chicken) Sing() {
fmt.Println(ch.Name + "在打鸣")
}
func (ch *Chicken) GetName() string {
return ch.Name
}
type Cat struct {
Name string
}
func (c *Cat) Sing() {
fmt.Println(c.Name + "在唱歌")
}
func (c *Cat) GetName() string {
return c.Name
}
scss
func handle(a Animal) {
if ch, ok := a.(*Chicken); ok {
fmt.Println("ch is Chicken")
}
fmt.Println(ch, ok)
}
func main() {
ch := Chicken{Name: "公鸡"}
ca := Cat{Name: "喵咪"}
handle(&ch)
handle(&ca)
}
通过 a.(*Chicken)
这个表达式断言 a
是否是Chicken
类型的实例,如果是,ok
值为 true
,然后执行 if
语句块中的代码;否则 ok
值为 false
,不执行 if
语句块中的代码。
go
switch ser := a.(type) {
case *Chicken:
fmt.Println(ser)
case *Cat:
fmt.Println(ser)
default:
fmt.Println("其他")
}
也可以通过switch语句做断言判断
空接口
在 Go 语言中,结构体与接口的实现关系是通过结构体所实现的方法在编译期推断出来的,如果我们定义一个空接口的话,那么显然所有的类都实现了这个接口,反过来,我们也可以通过空接口来指向任意类型, Go 的空接口实现简单,通过一个简单的字面量即可完成:
csharp
interface{}
指向任意类型变量
csharp
//基本类型
var v1 interface{} = 1 // 将 int 类型赋值给 interface{}
var v2 interface{} = "空接口" // 将 string 类型赋值给 interface{}
var v3 interface{} = true // 将 bool 类型赋值给 interface{}
//复合类型
var v4 interface{} = &v2 // 将指针类型赋值给 interface{}
var v5 interface{} = []int{1, 2, 3} // 将切片类型赋值给 interface{}
var v6 interface{} = struct{ // 将结构体类型赋值给 interface{}
id int
name string
}{1, "结构体"}
声明任意类型参数
go
func Printf(fmt string, args ...interface{})
func Println(args ...interface{}) ...
func (p *pp) printArg(arg interface{}, verb rune)
总结
- 接口是一种抽象类型,描述了一个对象的行为和功能,没有数据字段。接口只定义一组方法,不做具体的功能实现,实现接口的类型必须实现所有这些方法。
- 实现接口的类型可以是任何类型,包括结构体、基本数据类型、数组、切片、映射或函数等,只要实现了接口的所有方法,那么它就实现了该接口。
- 接口类型的值可以保存任何实现了该接口的类型。它们可以作为参数传递,也可以作为返回值返回。
- 接口可以嵌套在其他接口中,也可以通过嵌套其他接口来实现接口的组合。
- 空接口interface{}没有任何方法,因此可以用来表示任何类型的值。