什么是接口 interface
接口是一个非常重要的概念, 它描述了一组抽象的规范, 而不提供具体的实现 对于项目而言会使得代码更加优雅可读, 对于开发者而言也会减少很多心智负担, 代码风格逐渐形成了规范, 于是就有了现在人们所推崇的面向接口编程
在 Go 语言中, 接口主要用来约束行为, 其次也可以用作其他方面
基本接口
声明接口: type 接口名称 interface{ 行为(参数 参数类型) ?可选返回值 }
go
package main
import "fmt"
// 声明接口
type Animal interface {
breathe()
eat(food string) string
}
// 声明结构体
type Dog struct {
name string
}
// 虽然暂时没有用到这个方法, 但是必须实现,
// 否则就无法将 Dog 结构体传给 animalEatFood 方法作为参数
func (d Dog) breathe() {
fmt.Println("狗需要呼吸")
}
func (d Dog) eat(food string) string {
return d.name + "吃了" + food
}
// 使用接口: 动物吃东西方法
// 只要是实现了 Animal 这个接口的 结构体
// 都可以当作参数传入这个方法
func animalEatFood(animal Animal) {
msg := animal.eat("鱼")
fmt.Println(msg)
}
// 再声明一个接口体, 并且实现 Animal 接口
type Cat struct {
name string
}
func (c Cat) breathe() {
fmt.Println("猫需要呼吸")
}
func (c Cat) eat(food string) string {
return c.name + "吃了" + food
}
func (c Cat) catchMouse() {
fmt.Println("猫会抓老鼠")
}
func main() {
d := Dog{"小狗"}
animalEatFood(d)
d.breathe()
c := Cat{"小猫"}
animalEatFood(c)
c.catchMouse()
}内置接口
- compare: 可以比较相等的值的接口
- any: 允许任意类型的接口
仅约束数据类型的接口
空接口
表示允许任何类型, any 类型的实现原理就是空接口
go
package main
func main() {
// m := map[string]interface{}{}
m := map[string]any{}
m["name"] = "tom"
m["age"] = 18
}类型约束接口
只约束数据类型不约束行为(方法)
go
package main
import "fmt"
// 定义一个类型约束,只允许无符号整数类型
type UnsignedInteger interface {
uint | uint8 | uint16 | uint32 | uint64
}
// 检查年龄是否有效,使用泛型函数
func isValidAge[T UnsignedInteger](age T) bool {
// 由于是无符号整数,自然不能为负数
// 这里只检查是否在合理的人类年龄范围内
return age <= 150
}
// 计算物品数量总和
func sumCounts[T UnsignedInteger](counts []T) T {
var total T
for _, count := range counts {
total += count
}
return total
}
func main() {
// 年龄示例 - 不能为负数
var age uint8 = 25
fmt.Printf("年龄 %d 是否有效: %v\n", age, isValidAge(age))
// 计算总和
stock := []uint{10, 20, 30, 40}
total := sumCounts(stock)
fmt.Printf("总库存数量: %d\n", total)
// 尝试使用有符号整数会编译失败
// var negativeAge int = -5
// isValidAge(negativeAge)
// 负数导致编译错误:
// int does not satisfy UnsignedInteger (int missing in uint | uint8 | uint16 | uint32 | uint64)
}类型断言
类型断言通常用于判断某一接口类型的变量是否属于某一个类型
go
package main
import "fmt"
func main() {
// 断言接口类型的变量
var num any = 10 // => var num interface{} = 10
value, isOk := num.(int)
if isOk {
fmt.Println(value, isOk)
} else {
fmt.Println("error type")
}
// 强行断言非接口类型的变量
// 编译错误:
// invalid operation: fnum (variable of type float64) is not an interface
// var fnum float64 = 1.2
// fvalue, isOk := fnum.(int)
}类型判断
这个在 1.18 后不推荐了, 因为已经有泛型了, 不需要手动判断类型了
go
package main
import (
"errors"
"fmt"
)
// 使用泛型
func plus[T int | float64](a, b T) T {
return a + b
}
// 1.18之前无法使用泛型
func plus2(a, b interface{}) (interface{}, error) {
switch a.(type) { // 判断变量的类型
case int:
result := a.(int) + b.(int)
return result, nil
case float64:
result := a.(float64) + b.(float64)
return result, nil
default:
var zero interface{}
return zero, errors.New("unsupported type")
}
}
func main() {
fmt.Println(plus(1, 2)) // 3
fmt.Println(plus(1.2, 2.3)) // 3.5
fmt.Println("-----------")
fmt.Println(plus2(1, 2)) // 3 <nil>
fmt.Println(plus2(1.2, 2.3)) // 3.5 <nil>
}