初面网初面网

面向对象:接口与继承

Go 语言没有 class,面向对象通过 struct + 方法 + 接口来实现。接口(interface)用于定义行为集合、实现多态;继承通过结构体嵌入(struct embedding)实现组合式复用。

接口(interface)

接口定义了一组方法签名,任何类型只要实现了这些方法,就自动实现了该接口,不需要显式声明。

隐式实现:Go 中没有 implements 关键字,只要方法集合匹配就认为实现了接口

package main

import (
	"fmt"
	"math"
)

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

type Circle struct {
	Radius float64
}

// Circle 实现 Shape 接口
func (c Circle) Area() float64 {
	return math.Pi * c.Radius * c.Radius
}

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

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 = Circle{Radius: 5}
	fmt.Println("Circle Area:", s.Area())

	s = Rectangle{width: 10, height: 5}
	fmt.Println("Rect Area:", s.Area())
}

接口的特性

特性说明
隐式实现无需显式声明,方法匹配即实现
接口变量存储任意实现该接口的值,包含动态类型和动态值
零值接口的零值是 nil
空接口interface{},可以表示任何类型
package main

import "fmt"

func printValue(val interface{}) {
	fmt.Printf("Value: %v, Type: %T\n", val, val)
}

func main() {
	var i interface{}
	fmt.Println(i == nil)   // true,未初始化的接口零值为 nil

	printValue(42)          // Value: 42, Type: int
	printValue("hello")     // Value: hello, Type: string
	printValue(3.14)        // Value: 3.14, Type: float64
}

接口嵌套

接口可以通过嵌套组合出更复杂的行为。

package main

import "fmt"

type Reader interface {
	Read() string
}

type Writer interface {
	Write(data string)
}

type ReadWriter interface {
	Reader
	Writer
}

type File struct{}

func (f File) Read() string {
	return "Reading data"
}

func (f File) Write(data string) {
	fmt.Println("Writing data:", data)
}

func main() {
	var rw ReadWriter = File{}
	fmt.Println(rw.Read())
	rw.Write("Hello, Go!")
}

类型断言简述

从接口中提取具体类型使用类型断言:value, ok := iface.(Type)。断言失败时 ok 为 false,不会 panic。

类型断言和 type switch 的详细用法见 25-assertion.md

继承:结构体嵌入

Go 没有继承,使用结构体嵌入来实现组合式复用。子结构体可以"继承"父结构体的字段和方法。

package main

import "fmt"

// 父结构体
type Animal struct {
	Name string
}

func (a *Animal) Speak() {
	fmt.Println(a.Name, "says hello!")
}

// 子结构体,嵌入 Animal
type Dog struct {
	Animal
	Breed string
}

func main() {
	dog := Dog{
		Animal: Animal{Name: "Buddy"},
		Breed:  "Golden Retriever",
	}
	dog.Speak() // 调用父结构体的方法
	fmt.Println("Breed:", dog.Breed)
}

方法重写

子结构体可以定义同名方法覆盖父结构体的方法,仍然可以通过 父结构体名.方法 访问父类的方法。

package main

import "fmt"

type Vehicle struct {
	Brand string
}

func (v *Vehicle) Start() {
	fmt.Println(v.Brand, "started")
}

type Car struct {
	Vehicle
	Model string
}

// 重写 Start 方法
func (c *Car) Start() {
	fmt.Println(c.Brand, c.Model, "car started")
}

func main() {
	v := Vehicle{Brand: "Toyota"}
	c := Car{Vehicle: Vehicle{Brand: "Honda"}, Model: "Civic"}

	v.Start()       // Toyota started
	c.Start()       // Honda Civic car started(调用重写后的方法)
	c.Vehicle.Start() // Honda started(显式调用父类方法)
}

多态

通过接口实现类似继承的多态:不同的结构体实现同一个接口,赋给接口变量后统一调用。

package main

import "fmt"

type Speaker interface {
	Speak()
}

type Animal struct {
	Name string
}

func (a *Animal) Speak() {
	fmt.Println(a.Name, "says hello!")
}

type Cat struct {
	Animal
}

func (c *Cat) Speak() {
	fmt.Println(c.Name, "says meow!")
}

func main() {
	var speaker Speaker

	speaker = &Animal{Name: "Buddy"}
	speaker.Speak() // Buddy says hello!

	speaker = &Cat{Animal: Animal{Name: "Mimi"}}
	speaker.Speak() // Mimi says meow!(调用 Cat 自己的方法)
}

Go 与经典继承的区别

特性经典继承Go 的方式
代码复用通过继承通过组合(嵌入结构体)
多态通过继承和方法重写通过接口实现
关系"是一个"(is-a)关系"有一个"(has-a)或"实现了"关系
灵活性继承关系固定可以运行时组合

Go 通过组合避免了很多经典继承的问题(如脆弱的基类),同时提供了更大的灵活性

更新于 2026/8/13