Golang的接口是一种抽象类型,它定义了一组方法签名,只要某个类型实现了接口中声明的所有方法,就可以认为该类型实现了这个接口,不需要显式声明实现关系,这种设计让代码更加灵活且低耦合。

Golang接口的定义语法
在Golang中,使用interface关键字定义接口,接口内部只需要声明方法签名,不需要写方法的具体实现。接口定义的语法格式如下:
// 定义一个接口,名为Animal
type Animal interface {
// 方法签名:方法名 参数列表 返回值列表
Eat(food string) string
Run(speed int) bool
}
上述代码定义了一个Animal接口,包含Eat和Run两个方法,所有想要实现Animal接口的类型,都必须实现这两个方法,且方法的参数列表和返回值列表要和接口中声明的一致。
实现接口的条件
Golang中实现接口是隐式的,不需要像其他语言那样使用implements关键字声明,只需要满足两个条件:
- 实现接口中声明的所有方法
- 每个方法的名称、参数类型、返回值类型都和接口中声明的完全一致
普通类型实现接口示例
我们定义一个Dog结构体,让它实现前面定义的Animal接口:
package main
import "fmt"
// 定义Animal接口
type Animal interface {
Eat(food string) string
Run(speed int) bool
}
// 定义Dog结构体
type Dog struct {
Name string
}
// Dog实现Animal接口的Eat方法
func (d Dog) Eat(food string) string {
return fmt.Sprintf("%s吃了%s", d.Name, food)
}
// Dog实现Animal接口的Run方法
func (d Dog) Run(speed int) bool {
if speed > 0 {
fmt.Printf("%s以%d的速度奔跑n", d.Name, speed)
return true
}
return false
}
func main() {
// 声明Animal类型的变量
var animal Animal
// 将Dog实例赋值给animal变量
animal = Dog{Name: "小黑"}
// 调用接口方法
fmt.Println(animal.Eat("骨头"))
animal.Run(10)
}
运行上述代码会输出:
小黑吃了骨头 小黑以10的速度奔跑
指针类型实现接口
除了值类型可以实现接口,指针类型也可以实现接口,但是需要注意赋值时类型的匹配:
package main
import "fmt"
type Animal interface {
Eat(food string) string
}
type Cat struct {
Age int
}
// 指针接收者实现接口方法
func (c *Cat) Eat(food string) string {
return fmt.Sprintf("年龄%d岁的猫吃了%s", c.Age, food)
}
func main() {
var animal Animal
// 指针类型实现接口,只能赋值指针实例
animal = &Cat{Age: 2}
fmt.Println(animal.Eat("鱼"))
}
如果这里将&Cat{Age: 2}改成Cat{Age: 2},编译会报错,因为值类型的Cat没有实现Animal接口,只有指针类型的*Cat实现了该接口。
接口的类型断言
当我们拿到一个接口类型的变量时,有时候需要知道它具体是哪个类型实现的,这时候可以使用类型断言来获取具体的类型值:
package main
import "fmt"
type Animal interface {
Eat() string
}
type Bird struct{}
func (b Bird) Eat() string {
return "鸟吃虫子"
}
func main() {
var animal Animal = Bird{}
// 类型断言,判断animal是否是Bird类型
if bird, ok := animal.(Bird); ok {
fmt.Println("是Bird类型,调用Eat方法:", bird.Eat())
} else {
fmt.Println("不是Bird类型")
}
}
空接口的使用
Golang中还有一种特殊的接口叫做空接口,即interface{},它没有定义任何方法,所以所有类型都默认实现了空接口,空接口可以用来存储任意类型的值:
package main
import "fmt"
func main() {
var any interface{}
any = 123
fmt.Println(any)
any = "hello"
fmt.Println(any)
any = []int{1, 2, 3}
fmt.Println(any)
}
空接口在很多场景下非常有用,比如函数需要接收任意类型的参数时,就可以使用空接口作为参数类型。