Skip to content

第 12 章:接口(Go 核心特性)

12.1 什么是接口?接口的作用

接口是一种抽象类型,它定义了一组方法签名,而不实现这些方法。接口的主要作用是:

  • 实现多态
  • 解耦代码
  • 提高代码的可测试性和可扩展性

12.2 接口定义与实现(非侵入式)

接口定义

go
type Animal interface {
    Speak() string
    Move() string
}

接口实现

在 Go 中,接口的实现是隐式的,不需要显式声明。只要一个类型实现了接口的所有方法,它就自动实现了该接口:

go
type Dog struct {
    Name string
}

func (d Dog) Speak() string {
    return "Woof!"
}

func (d Dog) Move() string {
    return "Run"
}

type Cat struct {
    Name string
}

func (c Cat) Speak() string {
    return "Meow!"
}

func (c Cat) Move() string {
    return "Walk"
}

使用接口

go
func makeAnimalSpeak(a Animal) {
    fmt.Println(a.Speak())
}

func main() {
    dog := Dog{Name: "Rex"}
    cat := Cat{Name: "Whiskers"}
    
    makeAnimalSpeak(dog) // 输出 Woof!
    makeAnimalSpeak(cat) // 输出 Meow!
}

12.3 空接口 interface {}

空接口没有任何方法,因此所有类型都实现了空接口:

go
var i interface{}

// 可以存储任何类型的值
i = 42
fmt.Println(i)

i = "hello"
fmt.Println(i)

i = Dog{Name: "Rex"}
fmt.Println(i)

空接口的应用

  • 作为函数参数,接收任意类型
  • 作为 map 的值类型,存储不同类型的值
  • 作为 slice 的元素类型,存储不同类型的值

12.4 类型断言

类型断言用于将接口类型转换为具体类型:

基本用法

go
var i interface{} = 42

// 类型断言
v, ok := i.(int)
if ok {
    fmt.Println("i is an int:", v)
} else {
    fmt.Println("i is not an int")
}

类型断言与 switch

go
func process(i interface{}) {
    switch v := i.(type) {
    case int:
        fmt.Println("Integer:", v)
    case string:
        fmt.Println("String:", v)
    case bool:
        fmt.Println("Boolean:", v)
    default:
        fmt.Println("Unknown type")
    }
}

func main() {
    process(42)
    process("hello")
    process(true)
    process(Dog{Name: "Rex"})
}

12.5 接口实战:多态实现

案例 1:形状接口

go
package main

import "fmt"

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

type Rectangle struct {
    Width  float64
    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("Area: %.2f\n", s.Area())
    fmt.Printf("Perimeter: %.2f\n", s.Perimeter())
}

func main() {
    rect := Rectangle{Width: 10, Height: 5}
    circle := Circle{Radius: 7}
    
    fmt.Println("Rectangle:")
    printShapeInfo(rect)
    
    fmt.Println("\nCircle:")
    printShapeInfo(circle)
}

案例 2:工作接口

go
package main

import "fmt"

type Worker interface {
    Work() string
    Rest() string
}

type Engineer struct {
    Name string
}

func (e Engineer) Work() string {
    return e.Name + " is coding"
}

func (e Engineer) Rest() string {
    return e.Name + " is taking a break"
}

type Teacher struct {
    Name string
}

func (t Teacher) Work() string {
    return t.Name + " is teaching"
}

func (t Teacher) Rest() string {
    return t.Name + " is drinking coffee"
}

func simulateDay(w Worker) {
    fmt.Println(w.Work())
    fmt.Println(w.Rest())
}

func main() {
    engineer := Engineer{Name: "Alice"}
    teacher := Teacher{Name: "Bob"}
    
    fmt.Println("Engineer's day:")
    simulateDay(engineer)
    
    fmt.Println("\nTeacher's day:")
    simulateDay(teacher)
}

© 2026 编程马·菜鸟教程 版权所有