强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

Go 语言完全指南 / 11 - 接口:隐式实现、类型断言、空接口、设计模式

11 - 接口

11.1 接口基础

接口定义了一组方法签名,是 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() {
    var s Shape

    s = Circle{Radius: 5}
    fmt.Printf("圆形 - 面积: %.2f, 周长: %.2f\n", s.Area(), s.Perimeter())

    s = Rectangle{Width: 10, Height: 5}
    fmt.Printf("矩形 - 面积: %.2f, 周长: %.2f\n", s.Area(), s.Perimeter())
}

11.2 隐式实现

Go 的接口是隐式实现的——不需要 implements 关键字,只要实现了所有方法就自动满足接口。

// 这就是鸭子类型(Duck Typing)
// "如果它走起来像鸭子,叫起来像鸭子,那它就是鸭子"

type Writer interface {
    Write(p []byte) (n int, err error)
}

// 任何实现了 Write 方法的类型都自动满足 Writer 接口
type FileWriter struct{ path string }
func (f *FileWriter) Write(p []byte) (int, error) { /*...*/ return len(p), nil }

type Buffer struct{ data []byte }
func (b *Buffer) Write(p []byte) (int, error) { /*...*/ return len(p), nil }

type NetworkWriter struct{ addr string }
func (n *NetworkWriter) Write(p []byte) (int, error) { /*...*/ return len(p), nil }

接口组合

type Reader interface {
    Read(p []byte) (n int, err error)
}

type Closer interface {
    Close() error
}

// 组合接口
type ReadCloser interface {
    Reader
    Closer
}

type ReadWriteCloser interface {
    Reader
    Writer
    Closer
}

11.3 接口作为参数

package main

import "fmt"

type Notifier interface {
    Notify(message string)
}

type EmailNotifier struct{ Address string }
func (e EmailNotifier) Notify(msg string) {
    fmt.Printf("发送邮件到 %s: %s\n", e.Address, msg)
}

type SMSNotifier struct{ Phone string }
func (s SMSNotifier) Notify(msg string) {
    fmt.Printf("发送短信到 %s: %s\n", s.Phone, msg)
}

type SlackNotifier struct{ Channel string }
func (s SlackNotifier) Notify(msg string) {
    fmt.Printf("发送 Slack 到 #%s: %s\n", s.Channel, msg)
}

// 函数接受接口参数
func SendAlert(n Notifier, message string) {
    n.Notify(message)
}

// 接口切片
func Broadcast(notifiers []Notifier, message string) {
    for _, n := range notifiers {
        n.Notify(message)
    }
}

func main() {
    email := EmailNotifier{Address: "[email protected]"}
    sms := SMSNotifier{Phone: "+86-13800138000"}
    slack := SlackNotifier{Channel: "alerts"}

    SendAlert(email, "系统告警!")
    SendAlert(sms, "系统告警!")

    notifiers := []Notifier{email, sms, slack}
    Broadcast(notifiers, "全渠道通知")
}

11.4 空接口 interface

package main

import "fmt"

// interface{} 可以保存任意类型的值
func describe(i interface{}) {
    fmt.Printf("类型: %T, 值: %v\n", i, i)
}

// Go 1.18+ 可以用 any(interface{} 的别名)
func describeAny(i any) {
    fmt.Printf("类型: %T, 值: %v\n", i, i)
}

func main() {
    describe(42)
    describe("hello")
    describe(3.14)
    describe(true)
    describe([]int{1, 2, 3})
    describe(map[string]int{"a": 1})

    // 空接口作为通用容器
    var data []any
    data = append(data, 42, "hello", 3.14, true)
    fmt.Println(data)
}

11.5 类型断言和类型开关

package main

import "fmt"

func process(i any) {
    // 类型断言
    if s, ok := i.(string); ok {
        fmt.Println("字符串:", s)
    }

    // 类型开关
    switch v := i.(type) {
    case int:
        fmt.Printf("整数: %d\n", v)
    case string:
        fmt.Printf("字符串: %q\n", v)
    case bool:
        fmt.Printf("布尔: %v\n", v)
    case []int:
        fmt.Printf("整数切片: %v\n", v)
    case fmt.Stringer:
        fmt.Printf("Stringer: %s\n", v.String())
    default:
        fmt.Printf("未知类型 %T: %v\n", v, v)
    }
}

func main() {
    process(42)
    process("hello")
    process(true)
    process([]int{1, 2, 3})

    // 类型断言的 panic 风险
    var i any = "hello"
    // s := i.(int) // panic: interface conversion
    s, ok := i.(int) // 安全方式
    if !ok {
        fmt.Println("断言失败")
    }
    fmt.Println(s, ok)
}

11.6 常用标准库接口

// io 包
type Reader interface {
    Read(p []byte) (n int, err error)
}

type Writer interface {
    Write(p []byte) (n int, err error)
}

type Closer interface {
    Close() error
}

// fmt 包
type Stringer interface {
    String() string
}

// sort 包
type Interface interface {
    Len() int
    Less(i, j int) bool
    Swap(i, j int)
}

// error 接口
type error interface {
    Error() string
}

// http 包
type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}
// 实现 Stringer 接口
type User struct {
    Name string
    Age  int
}

func (u User) String() string {
    return fmt.Sprintf("%s (年龄: %d)", u.Name, u.Age)
}

func main() {
    u := User{Name: "Alice", Age: 30}
    fmt.Println(u) // Alice (年龄: 30)
}

11.7 接口设计模式

依赖注入

// 定义接口
type UserStore interface {
    Get(id int) (*User, error)
    Save(user *User) error
    Delete(id int) error
}

// 服务依赖接口
type UserService struct {
    store UserStore
}

func NewUserService(store UserStore) *UserService {
    return &UserService{store: store}
}

func (s *UserService) GetUser(id int) (*User, error) {
    return s.store.Get(id)
}

// 生产环境实现
type PostgresStore struct {
    db *sql.DB
}

func (s *PostgresStore) Get(id int) (*User, error) { /* SQL 查询 */ }
func (s *PostgresStore) Save(user *User) error      { /* SQL 插入 */ }
func (s *PostgresStore) Delete(id int) error         { /* SQL 删除 */ }

// 测试用 Mock
type MockStore struct {
    users map[int]*User
}

func (m *MockStore) Get(id int) (*User, error) { return m.users[id], nil }
func (m *MockStore) Save(user *User) error      { m.users[user.ID] = user; return nil }
func (m *MockStore) Delete(id int) error         { delete(m.users, id); return nil }

策略模式

type Compressor interface {
    Compress(data []byte) ([]byte, error)
}

type GzipCompressor struct{}
func (GzipCompressor) Compress(data []byte) ([]byte, error) { /* gzip */ return data, nil }

type ZlibCompressor struct{}
func (ZlibCompressor) Compress(data []byte) ([]byte, error) { /* zlib */ return data, nil }

type FileProcessor struct {
    compressor Compressor
}

func (fp *FileProcessor) Process(filename string) error {
    data, _ := os.ReadFile(filename)
    compressed, _ := fp.compressor.Compress(data)
    return os.WriteFile(filename+".gz", compressed, 0644)
}

中间件模式

type Handler func(http.ResponseWriter, *http.Request)

type Middleware func(Handler) Handler

func Logging(next Handler) Handler {
    return func(w http.ResponseWriter, r *http.Request) {
        log.Printf("%s %s", r.Method, r.URL.Path)
        next(w, r)
    }
}

func Auth(next Handler) Handler {
    return func(w http.ResponseWriter, r *http.Request) {
        if r.Header.Get("Authorization") == "" {
            http.Error(w, "Unauthorized", 401)
            return
        }
        next(w, r)
    }
}

func Chain(h Handler, middlewares ...Middleware) Handler {
    for i := len(middlewares) - 1; i >= 0; i-- {
        h = middlewares[i](h)
    }
    return h
}

11.8 接口的内部表示

interface{} 内部结构(两个指针):
┌─────────────────┐
│ type pointer  ───────→ 类型信息(*rtype)
│ data pointer  ───────→ 实际数据
└─────────────────┘

⚠️ 注意

  • 接口值为 nil 只有当类型和值都为 nil
  • 类型不为 nil 的接口值不等于 nil
func main() {
    var p *int = nil
    var i any = p
    fmt.Println(i == nil) // false!因为类型信息非 nil
    fmt.Println(i)        // <nil>
}

🏢 业务场景

  1. 依赖注入:面向接口编程,方便测试
  2. 插件系统:定义接口,实现可替换
  3. 中间件:HTTP、gRPC 中间件链
  4. 序列化:实现 json.Marshalerfmt.Stringer 等标准接口
  5. 策略模式:压缩算法、排序策略、日志输出等

📖 扩展阅读