接口
接口是方法签名的集合,是Go语言实现多态的核心机制。
接口定义
基本定义
go
// 定义接口
type Shape interface {
Area() float64
Perimeter() float64
}接口实现
Go中接口是隐式实现的,只要类型实现了接口的所有方法,就自动实现了该接口:
go
package main
import (
"fmt"
"math"
)
// 定义接口
type Shape interface {
Area() float64
Perimeter() float64
}
// Circle 实现Shape接口
type Circle struct {
Radius float64
}
func (c Circle) Area() float64 {
return math.Pi * c.Radius * c.Radius
}
func (c Circle) Perimeter() float64 {
return 2 * math.Pi * c.Radius
}
// Rectangle 实现Shape接口
type Rectangle struct {
Width, Height float64
}
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
func (r Rectangle) Perimeter() float64 {
return 2 * (r.Width + r.Height)
}
func main() {
circle := Circle{Radius: 5}
rectangle := Rectangle{Width: 4, Height: 6}
// 使用接口类型
shapes := []Shape{circle, rectangle}
for _, shape := range shapes {
fmt.Printf("面积: %.2f, 周长: %.2f\n", shape.Area(), shape.Perimeter())
}
}空接口
空接口 interface{} 或 any(Go 1.18+)可以存储任何类型的值:
go
func main() {
// 使用 interface{}
var i interface{}
i = 42
fmt.Println(i) // 42
i = "hello"
fmt.Println(i) // hello
i = []int{1, 2, 3}
fmt.Println(i) // [1 2 3]
// 使用 any(Go 1.18+)
var a any = "world"
fmt.Println(a) // world
}实际应用
go
func PrintAny(v any) {
fmt.Println(v)
}
func main() {
PrintAny(42)
PrintAny("hello")
PrintAny([]int{1, 2, 3})
}类型断言
类型断言用于获取接口值的具体类型:
go
func main() {
var i interface{} = "hello"
// 类型断言
s := i.(string)
fmt.Println(s) // hello
// 带检查的类型断言
s, ok := i.(string)
fmt.Println(s, ok) // hello true
n, ok := i.(int)
fmt.Println(n, ok) // 0 false
// 直接断言错误类型会panic
// n := i.(int) // panic: interface conversion
}类型开关
go
func typeSwitch(v interface{}) {
switch val := v.(type) {
case int:
fmt.Printf("整数: %d\n", val)
case string:
fmt.Printf("字符串: %s\n", val)
case bool:
fmt.Printf("布尔值: %t\n", val)
case []int:
fmt.Printf("整数切片: %v\n", val)
default:
fmt.Printf("未知类型: %T\n", val)
}
}
func main() {
typeSwitch(42)
typeSwitch("hello")
typeSwitch(true)
typeSwitch([]int{1, 2, 3})
typeSwitch(3.14)
}接口组合
接口可以嵌入其他接口:
go
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
// 组合接口
type ReadWriter interface {
Reader
Writer
}接口值
接口值由两部分组成:类型和值:
go
func main() {
var s Shape
fmt.Printf("%T, %v, %t\n", s, s, s == nil) // <nil>, <nil>, true
s = Circle{Radius: 5}
fmt.Printf("%T, %v\n", s, s) // main.Circle, {5}
s = nil
fmt.Printf("%T, %v, %t\n", s, s, s == nil) // <nil>, <nil>, true
}nil接口 vs 包含nil值的接口
go
func main() {
var s Shape
fmt.Println(s == nil) // true
var c *Circle
s = c // c是nil,但s不是nil接口
fmt.Println(s == nil) // false
// s的类型是 *Circle,值是 nil
fmt.Printf("%T, %v\n", s, s) // *main.Circle, <nil>
}常用标准接口
Stringer接口
go
type Stringer interface {
String() string
}
type Person struct {
Name string
Age int
}
func (p Person) String() string {
return fmt.Sprintf("%s (%d岁)", p.Name, p.Age)
}
func main() {
p := Person{Name: "张三", Age: 25}
fmt.Println(p) // 张三 (25岁)
}error接口
go
type error interface {
Error() string
}
type MyError struct {
Msg string
}
func (e *MyError) Error() string {
return fmt.Sprintf("错误: %s", e.Msg)
}
func doSomething() error {
return &MyError{Msg: "出错了"}
}Sorter接口
go
type Interface interface {
Len() int
Less(i, j int) bool
Swap(i, j int)
}
type ByLength []string
func (s ByLength) Len() int { return len(s) }
func (s ByLength) Less(i, j int) bool { return s[i] < s[j] }
func (s ByLength) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func main() {
fruits := []string{"peach", "banana", "kiwi"}
sort.Sort(ByLength(fruits))
fmt.Println(fruits) // [banana kiwi peach]
}接口设计原则
接口越小越好
go
// 好的设计 - 小接口
type Reader interface {
Read(p []byte) (n int, err error)
}
// 避免 - 大接口
type BigInterface interface {
Read(p []byte) (n int, err error)
Write(p []byte) (n int, err error)
Close() error
Flush() error
}接口由使用方定义
go
// 使用方定义自己需要的接口
type Storer interface {
Store(data []byte) error
}
// 实现方不需要知道接口的存在
type FileStorage struct{}
func (f *FileStorage) Store(data []byte) error {
// 实现
return nil
}实用示例
动物叫声
go
type Animal interface {
Speak() string
}
type Dog struct{}
func (d Dog) Speak() string {
return "汪汪汪"
}
type Cat struct{}
func (c Cat) Speak() string {
return "喵喵喵"
}
type Cow struct{}
func (c Cow) Speak() string {
return "哞哞哞"
}
func main() {
animals := []Animal{Dog{}, Cat{}, Cow{}}
for _, animal := range animals {
fmt.Println(animal.Speak())
}
}支付系统
go
type PaymentMethod interface {
Pay(amount float64) error
}
type CreditCard struct {
Number string
}
func (c CreditCard) Pay(amount float64) error {
fmt.Printf("使用信用卡 %s 支付 %.2f 元\n", c.Number, amount)
return nil
}
type Alipay struct {
Account string
}
func (a Alipay) Pay(amount float64) error {
fmt.Printf("使用支付宝 %s 支付 %.2f 元\n", a.Account, amount)
return nil
}
func ProcessPayment(method PaymentMethod, amount float64) {
method.Pay(amount)
}
func main() {
ProcessPayment(CreditCard{Number: "1234-5678"}, 100)
ProcessPayment(Alipay{Account: "user@example.com"}, 200)
}