Skip to content

接口

接口是方法签名的集合,是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)
}