Skip to content
<

Golang 结构体与接口

结构体(Struct)

结构体定义与初始化

go
package main

import "fmt"

// 定义结构体
type Person struct {
    Name    string
    Age     int
    Email   string
    Address string
}

// 嵌套结构体
type Contact struct {
    Phone  string
    Email  string
    Wechat string
}

type Employee struct {
    ID      int
    Name    string
    Contact Contact
    Salary  float64
}

func structBasicDemo() {
    // 方式1:字段名初始化
    person1 := Person{
        Name:    "张三",
        Age:     25,
        Email:   "zhangsan@example.com",
        Address: "北京",
    }

    // 方式2:按顺序初始化
    person2 := Person{"李四", 30, "lisi@example.com", "上海"}

    // 方式3:部分字段初始化(其他为零值)
    person3 := Person{Name: "王五", Age: 28}

    // 方式4:使用 new(返回指针)
    person4 := new(Person)
    person4.Name = "赵六"
    person4.Age = 35

    fmt.Printf("person1: %+v\n", person1)
    fmt.Printf("person2: %+v\n", person2)
    fmt.Printf("person3: %+v\n", person3)
    fmt.Printf("person4: %+v\n", *person4)

    // 嵌套结构体
    emp := Employee{
        ID:   1001,
        Name: "Jackson",
        Contact: Contact{
            Phone:  "13800138000",
            Email:  "jackson@example.com",
            Wechat: "jackson_wx",
        },
        Salary: 50000,
    }
    fmt.Printf("\n员工信息: %+v\n", emp)
    fmt.Printf("联系电话: %s\n", emp.Contact.Phone)
}

匿名结构体

go
func anonymousStructDemo() {
    // 定义并初始化匿名结构体
    student := struct {
        Name  string
        Grade int
        Score float64
    }{
        Name:  "小明",
        Grade: 3,
        Score: 95.5,
    }

    fmt.Printf("学生信息: %+v\n", student)

    // 匿名结构体切片
    students := []struct {
        Name  string
        Score int
    }{
        {"张三", 85},
        {"李四", 90},
        {"王五", 88},
    }

    fmt.Println("\n学生成绩:")
    for _, s := range students {
        fmt.Printf("%s: %d\n", s.Name, s.Score)
    }
}

结构体方法

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

// 指针接收者方法
func (r *Rectangle) Scale(factor float64) {
    r.Width *= factor
    r.Height *= factor
}

func (r *Rectangle) SetDimensions(width, height float64) {
    r.Width = width
    r.Height = height
}

func structMethodDemo() {
    rect := Rectangle{Width: 10, Height: 5}

    fmt.Printf("原始尺寸: %.2f × %.2f\n", rect.Width, rect.Height)
    fmt.Printf("面积: %.2f\n", rect.Area())
    fmt.Printf("周长: %.2f\n", rect.Perimeter())

    // 修改结构体
    rect.Scale(2)
    fmt.Printf("\n放大2倍后: %.2f × %.2f\n", rect.Width, rect.Height)
    fmt.Printf("面积: %.2f\n", rect.Area())

    rect.SetDimensions(15, 8)
    fmt.Printf("\n设置新尺寸: %.2f × %.2f\n", rect.Width, rect.Height)
}

结构体嵌入(组合)

go
// 基础结构体
type Animal struct {
    Name   string
    Age    int
    Weight float64
}

func (a Animal) Eat() {
    fmt.Printf("%s 正在吃东西\n", a.Name)
}

func (a Animal) Sleep() {
    fmt.Printf("%s 正在睡觉\n", a.Name)
}

// 嵌入 Animal
type Dog struct {
    Animal // 匿名字段(嵌入)
    Breed  string
}

func (d Dog) Bark() {
    fmt.Printf("%s 正在叫: 汪汪汪!\n", d.Name)
}

type Cat struct {
    Animal
    Color string
}

func (c Cat) Meow() {
    fmt.Printf("%s 正在叫: 喵喵喵!\n", c.Name)
}

func structEmbeddingDemo() {
    // 创建 Dog 实例
    dog := Dog{
        Animal: Animal{
            Name:   "旺财",
            Age:    3,
            Weight: 15.5,
        },
        Breed: "金毛",
    }

    // 可以直接访问嵌入结构体的字段
    fmt.Printf("狗的名字: %s\n", dog.Name)
    fmt.Printf("狗的品种: %s\n", dog.Breed)

    // 调用嵌入结构体的方法
    dog.Eat()
    dog.Sleep()
    dog.Bark()

    // 创建 Cat 实例
    fmt.Println()
    cat := Cat{
        Animal: Animal{Name: "咪咪", Age: 2, Weight: 4.5},
        Color:  "白色",
    }

    fmt.Printf("猫的名字: %s, 颜色: %s\n", cat.Name, cat.Color)
    cat.Eat()
    cat.Meow()
}

结构体标签(Tag)

go
import (
    "encoding/json"
    "fmt"
)

type User struct {
    ID       int    `json:"id"`
    Username string `json:"username"`
    Email    string `json:"email"`
    Password string `json:"-"` // 忽略此字段
    Age      int    `json:"age,omitempty"` // 为空时忽略
}

func structTagDemo() {
    user := User{
        ID:       1,
        Username: "jackson",
        Email:    "jackson@example.com",
        Password: "secret123",
        Age:      25,
    }

    // 序列化为 JSON
    jsonData, err := json.Marshal(user)
    if err != nil {
        fmt.Println("JSON 序列化错误:", err)
        return
    }

    fmt.Println("JSON 数据:", string(jsonData))

    // 反序列化
    jsonStr := `{"id":2,"username":"alice","email":"alice@example.com","age":30}`
    var newUser User
    err = json.Unmarshal([]byte(jsonStr), &newUser)
    if err != nil {
        fmt.Println("JSON 反序列化错误:", err)
        return
    }

    fmt.Printf("反序列化用户: %+v\n", newUser)
}

接口(Interface)

接口定义与实现

go
// 定义接口
type Shape interface {
    Area() float64
    Perimeter() float64
}

// 矩形实现 Shape 接口
type Rect struct {
    Width  float64
    Height float64
}

func (r Rect) Area() float64 {
    return r.Width * r.Height
}

func (r Rect) Perimeter() float64 {
    return 2 * (r.Width + r.Height)
}

// 圆形实现 Shape 接口
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\n", s.Area(), s.Perimeter())
}

func interfaceBasicDemo() {
    rect := Rect{Width: 10, Height: 5}
    circle := Circle{Radius: 7}

    fmt.Println("矩形信息:")
    printShapeInfo(rect)

    fmt.Println("\n圆形信息:")
    printShapeInfo(circle)

    // 接口切片
    shapes := []Shape{
        Rect{Width: 5, Height: 3},
        Circle{Radius: 4},
        Rect{Width: 8, Height: 6},
    }

    fmt.Println("\n所有图形:")
    for i, shape := range shapes {
        fmt.Printf("图形 %d - ", i+1)
        printShapeInfo(shape)
    }
}

空接口

go
func emptyInterfaceDemo() {
    // 空接口可以存储任何类型
    var any interface{}

    any = 42
    fmt.Printf("int: %v\n", any)

    any = "Hello"
    fmt.Printf("string: %v\n", any)

    any = true
    fmt.Printf("bool: %v\n", any)

    any = []int{1, 2, 3}
    fmt.Printf("slice: %v\n", any)

    // 空接口切片
    data := []interface{}{
        "Jackson",
        25,
        true,
        3.14,
        []int{1, 2, 3},
    }

    fmt.Println("\n空接口切片:")
    for i, v := range data {
        fmt.Printf("%d: %v (类型: %T)\n", i, v, v)
    }
}

类型断言

go
func typeAssertionDemo() {
    var i interface{} = "Hello, World"

    // 类型断言(不安全)
    // s := i.(string)
    // fmt.Println(s)

    // 类型断言(安全)
    s, ok := i.(string)
    if ok {
        fmt.Printf("字符串值: %s\n", s)
    } else {
        fmt.Println("不是字符串类型")
    }

    // 尝试错误的类型断言
    n, ok := i.(int)
    if ok {
        fmt.Printf("整数值: %d\n", n)
    } else {
        fmt.Println("不是整数类型")
    }
}

类型选择(Type Switch)

go
func describe(i interface{}) {
    switch v := i.(type) {
    case int:
        fmt.Printf("整数: %d\n", v)
    case string:
        fmt.Printf("字符串: %s (长度: %d)\n", v, len(v))
    case bool:
        fmt.Printf("布尔值: %t\n", v)
    case float64:
        fmt.Printf("浮点数: %.2f\n", v)
    case []int:
        fmt.Printf("整数切片: %v\n", v)
    case Person:
        fmt.Printf("Person 结构体: %+v\n", v)
    case nil:
        fmt.Println("nil 值")
    default:
        fmt.Printf("未知类型: %T\n", v)
    }
}

func typeSwitchDemo() {
    describe(42)
    describe("Hello")
    describe(true)
    describe(3.14)
    describe([]int{1, 2, 3})
    describe(Person{Name: "Jackson", Age: 25})
    describe(nil)
}

接口嵌套

go
// 基础接口
type Reader interface {
    Read() string
}

type Writer interface {
    Write(data string)
}

// 嵌套接口
type ReadWriter interface {
    Reader
    Writer
}

// 实现 ReadWriter 接口
type File struct {
    Name    string
    Content string
}

func (f *File) Read() string {
    return f.Content
}

func (f *File) Write(data string) {
    f.Content = data
}

func interfaceEmbeddingDemo() {
    file := &File{Name: "test.txt"}

    // File 实现了 ReadWriter 接口
    var rw ReadWriter = file

    rw.Write("Hello, Golang!")
    fmt.Printf("文件内容: %s\n", rw.Read())

    // 也可以作为单独的接口使用
    var r Reader = file
    fmt.Printf("读取内容: %s\n", r.Read())

    var w Writer = file
    w.Write("Updated content")
    fmt.Printf("更新后内容: %s\n", file.Read())
}

接口的实际应用

go
// 定义数据库接口
type Database interface {
    Connect() error
    Query(sql string) ([]map[string]interface{}, error)
    Close() error
}

// MySQL 实现
type MySQL struct {
    Host string
    Port int
}

func (m *MySQL) Connect() error {
    fmt.Printf("连接到 MySQL: %s:%d\n", m.Host, m.Port)
    return nil
}

func (m *MySQL) Query(sql string) ([]map[string]interface{}, error) {
    fmt.Printf("MySQL 执行查询: %s\n", sql)
    return []map[string]interface{}{
        {"id": 1, "name": "张三"},
        {"id": 2, "name": "李四"},
    }, nil
}

func (m *MySQL) Close() error {
    fmt.Println("关闭 MySQL 连接")
    return nil
}

// PostgreSQL 实现
type PostgreSQL struct {
    Host string
    Port int
}

func (p *PostgreSQL) Connect() error {
    fmt.Printf("连接到 PostgreSQL: %s:%d\n", p.Host, p.Port)
    return nil
}

func (p *PostgreSQL) Query(sql string) ([]map[string]interface{}, error) {
    fmt.Printf("PostgreSQL 执行查询: %s\n", sql)
    return []map[string]interface{}{
        {"id": 1, "name": "王五"},
    }, nil
}

func (p *PostgreSQL) Close() error {
    fmt.Println("关闭 PostgreSQL 连接")
    return nil
}

// 使用接口的函数
func executeQuery(db Database, sql string) {
    db.Connect()
    defer db.Close()

    results, err := db.Query(sql)
    if err != nil {
        fmt.Println("查询错误:", err)
        return
    }

    fmt.Println("查询结果:", results)
}

func interfaceApplicationDemo() {
    mysql := &MySQL{Host: "localhost", Port: 3306}
    postgresql := &PostgreSQL{Host: "localhost", Port: 5432}

    fmt.Println("=== MySQL 查询 ===")
    executeQuery(mysql, "SELECT * FROM users")

    fmt.Println("\n=== PostgreSQL 查询 ===")
    executeQuery(postgresql, "SELECT * FROM users")
}

完整示例:图书管理系统

go
package main

import "fmt"

// 图书接口
type Book interface {
    GetInfo() string
    GetPrice() float64
}

// 纸质书
type PaperBook struct {
    Title     string
    Author    string
    Price     float64
    PageCount int
}

func (p PaperBook) GetInfo() string {
    return fmt.Sprintf("《%s》- %s (纸质书, %d页)", p.Title, p.Author, p.PageCount)
}

func (p PaperBook) GetPrice() float64 {
    return p.Price
}

// 电子书
type EBook struct {
    Title    string
    Author   string
    Price    float64
    FileSize float64 // MB
}

func (e EBook) GetInfo() string {
    return fmt.Sprintf("《%s》- %s (电子书, %.2fMB)", e.Title, e.Author, e.FileSize)
}

func (e EBook) GetPrice() float64 {
    return e.Price
}

// 图书馆
type Library struct {
    Name  string
    Books []Book
}

func (l *Library) AddBook(book Book) {
    l.Books = append(l.Books, book)
    fmt.Printf("已添加: %s\n", book.GetInfo())
}

func (l *Library) ListBooks() {
    fmt.Printf("\n=== %s 图书列表 ===\n", l.Name)
    totalPrice := 0.0
    for i, book := range l.Books {
        fmt.Printf("%d. %s - ¥%.2f\n", i+1, book.GetInfo(), book.GetPrice())
        totalPrice += book.GetPrice()
    }
    fmt.Printf("\n总价值: ¥%.2f\n", totalPrice)
}

func main() {
    library := &Library{Name: "Jackson图书馆"}

    // 添加纸质书
    library.AddBook(PaperBook{
        Title:     "Go语言编程",
        Author:    "张三",
        Price:     89.00,
        PageCount: 500,
    })

    library.AddBook(PaperBook{
        Title:     "算法导论",
        Author:    "李四",
        Price:     128.00,
        PageCount: 800,
    })

    // 添加电子书
    library.AddBook(EBook{
        Title:    "深入理解计算机系统",
        Author:   "王五",
        Price:    68.00,
        FileSize: 15.5,
    })

    library.AddBook(EBook{
        Title:    "设计模式",
        Author:   "赵六",
        Price:    45.00,
        FileSize: 8.2,
    })

    // 列出所有图书
    library.ListBooks()
}

小结

  • 结构体:自定义复合数据类型
  • 结构体方法:值接收者 vs 指针接收者
  • 结构体嵌入:实现组合和代码复用
  • 结构体标签:用于序列化、验证等
  • 接口:定义行为规范,实现多态
  • 空接口:可以存储任何类型
  • 类型断言:从接口获取具体类型
  • 类型选择:根据类型执行不同逻辑
  • 接口嵌套:组合多个接口
  • 面向接口编程:提高代码灵活性和可测试性