Go接口Skill go-interfaces

Go接口技能用于掌握Go编程语言中的接口系统,通过隐式实现和组合模式创建灵活、解耦的代码,适用于设计API、抽象、实现多态性、依赖注入等场景。关键词:Go编程、接口设计、鸭子类型、组合模式、API设计、抽象、软件开发、后端开发、代码解耦、可测试性。

后端开发 0 次安装 2 次浏览 更新于 3/25/2026

name: go-interfaces user-invocable: false description: 当涉及Go接口包括接口设计、鸭子类型和组合模式时使用。当设计Go API和抽象时使用。 allowed-tools:

  • Bash
  • Read

Go接口

掌握Go的接口系统,通过隐式实现和组合模式创建灵活、解耦的代码。

基本接口

定义和实现接口:

package main

import "fmt"

// 定义接口
type Writer interface {
    Write(p []byte) (n int, err error)
}

// 实现接口(隐式)
type ConsoleWriter struct{}

func (cw ConsoleWriter) Write(p []byte) (n int, err error) {
    fmt.Print(string(p))
    return len(p), nil
}

func main() {
    var w Writer = ConsoleWriter{}
    w.Write([]byte("Hello, World!
"))
}

接口中的多个方法:

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

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

// 实现ReadWriter
type File struct {
    name string
}

func (f *File) Read(p []byte) (n int, err error) {
    // 实现
    return 0, nil
}

func (f *File) Write(p []byte) (n int, err error) {
    // 实现
    return len(p), nil
}

空接口

使用interface{}(Go 1.18+中的any):

// 接受任何类型
func printValue(v interface{}) {
    fmt.Println(v)
}

// 现代语法(Go 1.18+)
func printAny(v any) {
    fmt.Println(v)
}

func main() {
    printValue(42)
    printValue("hello")
    printValue(true)

    printAny(3.14)
}

类型断言:

func processValue(v interface{}) {
    // 类型断言
    if str, ok := v.(string); ok {
        fmt.Println("字符串:", str)
    }

    // 类型切换
    switch val := v.(type) {
    case int:
        fmt.Println("整数:", val)
    case string:
        fmt.Println("字符串:", val)
    case bool:
        fmt.Println("布尔值:", val)
    default:
        fmt.Println("未知类型")
    }
}

接口组合

嵌入接口:

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
}

// 组合接口
type ReadWriter interface {
    Reader
    Writer
}

type ReadWriteCloser interface {
    Reader
    Writer
    Closer
}

// 标准库示例
import "io"

func useReadWriteCloser(rwc io.ReadWriteCloser) {
    // 可以调用Read、Write和Close
    rwc.Write([]byte("data"))
    rwc.Close()
}

常见接口

标准库接口:

// Stringer接口
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)
}

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

type MyError struct {
    Message string
}

func (e MyError) Error() string {
    return e.Message
}

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

type ByAge []Person

func (a ByAge) Len() int           { return len(a) }
func (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age }
func (a ByAge) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }

接口设计模式

小接口:

// 好:小、专注的接口
type Getter interface {
    Get(key string) (value string, exists bool)
}

type Setter interface {
    Set(key, value string)
}

type Deleter interface {
    Delete(key string)
}

// 按需组合
type Cache interface {
    Getter
    Setter
    Deleter
}

接受接口,返回结构体:

// 接受接口参数
func processReader(r io.Reader) error {
    data, err := io.ReadAll(r)
    if err != nil {
        return err
    }
    fmt.Println(string(data))
    return nil
}

// 返回具体类型
func newConfig() *Config {
    return &Config{
        Host: "localhost",
        Port: 8080,
    }
}

type Config struct {
    Host string
    Port int
}

Nil接口

理解nil接口:

func checkNil() {
    var i interface{}
    fmt.Println(i == nil) // true

    var p *Person
    i = p
    fmt.Println(i == nil) // false!(类型已设置,值为nil)

    // 正确的nil检查
    v, ok := i.(*Person)
    fmt.Println(v == nil, ok) // true, true
}

接口满足

检查接口实现:

// 编译时检查
var _ io.Writer = (*MyWriter)(nil)
var _ io.Reader = (*MyReader)(nil)

type MyWriter struct{}

func (w *MyWriter) Write(p []byte) (n int, err error) {
    return len(p), nil
}

// 如果MyWriter未实现Writer,编译失败

鸭子类型

隐式接口满足:

// 无需显式"implements"关键字
type Duck interface {
    Quack()
    Walk()
}

type RealDuck struct{}

func (d RealDuck) Quack() {
    fmt.Println("嘎嘎!")
}

func (d RealDuck) Walk() {
    fmt.Println("摇摇摆摆")
}

type Robot struct{}

func (r Robot) Quack() {
    fmt.Println("哔哔嘎嘎")
}

func (r Robot) Walk() {
    fmt.Println("*机械行走声*")
}

func makeDuckDoThings(d Duck) {
    d.Quack()
    d.Walk()
}

func main() {
    makeDuckDoThings(RealDuck{})
    makeDuckDoThings(Robot{})
}

多态性

使用接口实现多态性:

type Shape interface {
    Area() float64
    Perimeter() float64
}

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)
}

type Circle struct {
    Radius float64
}

func (c Circle) Area() float64 {
    return 3.14159 * c.Radius * c.Radius
}

func (c Circle) Perimeter() float64 {
    return 2 * 3.14159 * c.Radius
}

func printShapeInfo(s Shape) {
    fmt.Printf("面积: %.2f, 周长: %.2f
",
        s.Area(), s.Perimeter())
}

func main() {
    shapes := []Shape{
        Rectangle{Width: 10, Height: 5},
        Circle{Radius: 7},
    }

    for _, shape := range shapes {
        printShapeInfo(shape)
    }
}

依赖注入

使用接口提高可测试性:

// 为依赖定义接口
type UserRepository interface {
    GetUser(id int) (*User, error)
    SaveUser(user *User) error
}

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

func (r *PostgresUserRepo) GetUser(id int) (*User, error) {
    // 数据库查询
    return &User{}, nil
}

func (r *PostgresUserRepo) SaveUser(user *User) error {
    // 数据库插入/更新
    return nil
}

// 测试实现
type MockUserRepo struct {
    users map[int]*User
}

func (m *MockUserRepo) GetUser(id int) (*User, error) {
    user, exists := m.users[id]
    if !exists {
        return nil, errors.New("用户未找到")
    }
    return user, nil
}

func (m *MockUserRepo) SaveUser(user *User) error {
    m.users[user.ID] = user
    return nil
}

// 服务依赖接口,而非具体类型
type UserService struct {
    repo UserRepository
}

func (s *UserService) GetUserName(id int) (string, error) {
    user, err := s.repo.GetUser(id)
    if err != nil {
        return "", err
    }
    return user.Name, nil
}

type User struct {
    ID   int
    Name string
}

建造者模式与接口

流式接口模式:

type QueryBuilder interface {
    Select(fields ...string) QueryBuilder
    From(table string) QueryBuilder
    Where(condition string) QueryBuilder
    Build() string
}

type sqlQueryBuilder struct {
    selectFields []string
    fromTable    string
    whereClause  string
}

func NewQueryBuilder() QueryBuilder {
    return &sqlQueryBuilder{}
}

func (b *sqlQueryBuilder) Select(fields ...string) QueryBuilder {
    b.selectFields = fields
    return b
}

func (b *sqlQueryBuilder) From(table string) QueryBuilder {
    b.fromTable = table
    return b
}

func (b *sqlQueryBuilder) Where(condition string) QueryBuilder {
    b.whereClause = condition
    return b
}

func (b *sqlQueryBuilder) Build() string {
    query := "SELECT " + strings.Join(b.selectFields, ", ")
    query += " FROM " + b.fromTable
    if b.whereClause != "" {
        query += " WHERE " + b.whereClause
    }
    return query
}

func main() {
    query := NewQueryBuilder().
        Select("id", "name", "email").
        From("users").
        Where("age > 18").
        Build()

    fmt.Println(query)
}

策略模式

实现策略模式:

type PaymentStrategy interface {
    Pay(amount float64) error
}

type CreditCardPayment struct {
    CardNumber string
}

func (c *CreditCardPayment) Pay(amount float64) error {
    fmt.Printf("使用信用卡 %s 支付 %.2f
",
        amount, c.CardNumber)
    return nil
}

type PayPalPayment struct {
    Email string
}

func (p *PayPalPayment) Pay(amount float64) error {
    fmt.Printf("通过PayPal向 %s 支付 %.2f
",
        amount, p.Email)
    return nil
}

type ShoppingCart struct {
    paymentMethod PaymentStrategy
}

func (cart *ShoppingCart) SetPaymentMethod(pm PaymentStrategy) {
    cart.paymentMethod = pm
}

func (cart *ShoppingCart) Checkout(amount float64) error {
    return cart.paymentMethod.Pay(amount)
}

func main() {
    cart := &ShoppingCart{}

    cart.SetPaymentMethod(&CreditCardPayment{CardNumber: "1234-5678"})
    cart.Checkout(100.00)

    cart.SetPaymentMethod(&PayPalPayment{Email: "user@example.com"})
    cart.Checkout(50.00)
}

适配器模式

适配接口:

// 第三方日志器
type ThirdPartyLogger struct{}

func (t *ThirdPartyLogger) LogMessage(msg string, level int) {
    fmt.Printf("[级别 %d] %s
", level, msg)
}

// 我们的应用接口
type Logger interface {
    Info(msg string)
    Error(msg string)
}

// 适配器
type LoggerAdapter struct {
    thirdParty *ThirdPartyLogger
}

func (a *LoggerAdapter) Info(msg string) {
    a.thirdParty.LogMessage(msg, 0)
}

func (a *LoggerAdapter) Error(msg string) {
    a.thirdParty.LogMessage(msg, 2)
}

func useLogger(logger Logger) {
    logger.Info("应用启动")
    logger.Error("发生错误")
}

func main() {
    adapter := &LoggerAdapter{
        thirdParty: &ThirdPartyLogger{},
    }
    useLogger(adapter)
}

何时使用此技能

使用go-interfaces当您需要:

  • 定义行为契约而无实现
  • 启用多态性和代码重用
  • 创建可测试代码与依赖注入
  • 实现设计模式(策略、适配器等)
  • 构建插件系统或可扩展架构
  • 在大型应用中解耦组件
  • 在测试中模拟依赖
  • 在Go中遵循SOLID原则
  • 创建灵活、可维护的API
  • 支持相同行为的多种实现

最佳实践

  • 保持接口小而专注(1-3个方法)
  • 接受接口,返回具体类型
  • 在接口使用处定义,而非实现处
  • 使用接口组合处理复杂接口
  • 除非绝对必要,不使用空接口
  • 在编译时验证接口实现
  • 在接口注释中记录预期行为
  • 偏好多个小接口而非大接口
  • 适用时使用标准库接口
  • 以-er后缀命名接口(Reader、Writer等)

常见陷阱

  • 使接口过大或过于通用
  • 定义未使用的接口“以防万一”
  • 返回接口而非具体类型
  • 未正确处理nil接口值
  • 对简单代码过度抽象
  • 忘记接口是隐式满足的
  • 过度使用空接口
  • 未记录接口契约
  • 为单一实现创建接口
  • 混淆nil值与nil接口

资源