【go语言】接口 interface

接口是一组方法签名的集合。Go 语言的接口是隐式实现的:一个类型只要实现了接口中的所有方法,就自动满足这个接口,不需要显式声明。

1. 接口的定义与实现

type Animal interface {
    Speak() string
}

type Dog struct{}
type Cat struct{}

func (d Dog) Speak() string { return "汪汪" }
func (c Cat) Speak() string { return "喵喵" }

func main() {
    var a Animal
    a = Dog{}
    fmt.Println(a.Speak()) // 汪汪
    a = Cat{}
    fmt.Println(a.Speak()) // 喵喵
}

Dog 和 Cat 都实现了 Speak 方法,因此都满足 Animal 接口。接口变量可以存放任何实现了该接口的值,这也是 Go 实现多态的方式。

2. 空接口

没有任何方法的接口叫空接口 interface{},所有类型都实现了空接口,因此空接口可以存放任意类型的值:

var any interface{}
any = 100
any = "hello"
any = []int{1, 2, 3}
fmt.Println(any)

Go 1.18 之后可以用内置类型别名 any 代替 interface{},两者完全等价。

3. 类型断言

从接口变量中取出原始类型的值需要类型断言:

var a Animal = Dog{}

dog, ok := a.(Dog)   // 带检查的断言
if ok {
    fmt.Println("是狗:", dog.Speak())
}

// 多分支判断推荐类型switch
switch v := a.(type) {
case Dog:
    fmt.Println("Dog:", v.Speak())
case Cat:
    fmt.Println("Cat:", v.Speak())
default:
    fmt.Println("未知类型")
}

不带 ok 的断言在类型不匹配时会 panic,生产代码建议始终使用带 ok 的形式。

4. 接口值与 nil 比较

接口值由「类型信息 + 值」两部分组成。把一个值为 nil 的具体类型指针赋给接口后,接口并不等于 nil,这是常见的坑:

type MyErr struct{}
func (e *MyErr) Error() string { return "err" }

func do() error {
    var e *MyErr // 返回了类型非nil、值nil的接口
    return e
}

err := do()
fmt.Println(err != nil) // true!

函数返回 error 时注意不要返回具体类型的 nil 指针,直接返回 nil 即可。

© 版权声明
THE END
喜欢就支持一下吧
点赞12 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容