golang编程核心-结构体与面向对象编程

在传统的面向对象语言中,类是封装数据和行为的核心概念。Go语言选择了不同的道路——它没有类,而是使用结构体(struct)来组织数据,使用方法(method)来定义行为。

// 基本结构体定义
type Person struct {
    Name string
    Age  int
    City string
}

// 使用结构体
func main() {
    // 创建结构体实例
    person := Person{
        Name: "Alice",
        Age:  30,
        City: "Beijing",
    }
    
    fmt.Printf("姓名: %s, 年龄: %d, 城市: %s
", 
        person.Name, person.Age, person.City)
}

结构体的初始化:

// 多种初始化方式
func structInitialization() {
    // 1. 零值初始化
    var p1 Person
    fmt.Printf("零值: %+v
", p1) // {Name: Age:0 City:}
    
    // 2. 字面量初始化
    p2 := Person{
        Name: "Bob",
        Age:  25,
        City: "Shanghai",
    }
    
    // 3. 部分字段初始化
    p3 := Person{
        Name: "Charlie",
        // Age和City使用零值
    }
    
    // 4. 使用new函数
    p4 := new(Person)
    p4.Name = "David"
    p4.Age = 35
    
    // 5. 匿名结构体
    p5 := struct {
        Name string
        Age  int
    }{
        Name: "Eve",
        Age:  28,
    }
    
    fmt.Printf("p2: %+v
", p2)
    fmt.Printf("p3: %+v
", p3)
    fmt.Printf("p4: %+v
", p4)
    fmt.Printf("p5: %+v
", p5)
}

方法的定义:

值接收者方法:

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 main() {
    rect := Rectangle{Width: 10, Height: 5}
    
    fmt.Printf("面积: %.2f
", rect.Area())       // 50.00
    fmt.Printf("周长: %.2f
", rect.Perimeter())  // 30.00
}

指针接收者方法:

type Counter struct {
    value int
}

// 指针接收者方法 - 可以修改结构体
func (c *Counter) Increment() {
    c.value++
}

func (c *Counter) Decrement() {
    c.value--
}

func (c *Counter) Value() int {
    return c.value
}

// 使用示例
func main() {
    counter := &Counter{value: 0}
    
    counter.Increment()
    counter.Increment()
    counter.Decrement()
    
    fmt.Printf("当前值: %d
", counter.Value()) // 1
}

值接收者 vs 指针接收者

何时使用值接收者

type Point struct {
    X, Y float64
}

// 值接收者 - 不修改结构体,且结构体较小
func (p Point) Distance() float64 {
    return math.Sqrt(p.X*p.X + p.Y*p.Y)
}

func (p Point) String() string {
    return fmt.Sprintf("(%v, %v)", p.X, p.Y)
}

// 使用示例
func main() {
    p := Point{3, 4}
    fmt.Printf("点: %s, 距离: %.2f
", p, p.Distance())
}

何时使用指针接收者

type BankAccount struct {
    balance float64
    owner   string
}

// 指针接收者 - 需要修改结构体
func (ba *BankAccount) Deposit(amount float64) {
    ba.balance += amount
}

func (ba *BankAccount) Withdraw(amount float64) error {
    if amount > ba.balance {
        return errors.New("余额不足")
    }
    ba.balance -= amount
    return nil
}

func (ba *BankAccount) Balance() float64 {
    return ba.balance
}

// 使用示例
func main() {
    account := &BankAccount{balance: 1000, owner: "Alice"}
    
    account.Deposit(500)
    fmt.Printf("存款后余额: %.2f
", account.Balance())
    
    err := account.Withdraw(200)
    if err != nil {
        fmt.Println("取款失败:", err)
    } else {
        fmt.Printf("取款后余额: %.2f
", account.Balance())
    }
}

方法集

方法集规则

type T struct {
    value int
}

// 值接收者方法
func (t T) ValueMethod() {
    fmt.Println("值方法")
}

// 指针接收者方法
func (t *T) PointerMethod() {
    fmt.Println("指针方法")
}

func methodSetDemo() {
    var t T
    var pt *T = &t
    
    // 值类型的方法集
    t.ValueMethod()   // 可以调用
    t.PointerMethod() // 可以调用(Go自动转换)
    
    // 指针类型的方法集
    pt.ValueMethod()   // 可以调用(Go自动解引用)
    pt.PointerMethod() // 可以调用
}

结构体嵌入

匿名字段

// 基础结构体
type Address struct {
    Street string
    City   string
    Zip    string
}

// 嵌入结构体
type Person struct {
    Name    string
    Age     int
    Address // 匿名字段
}

// 使用示例
func main() {
    person := Person{
        Name: "Alice",
        Age:  30,
        Address: Address{
            Street: "123 Main St",
            City:   "Beijing",
            Zip:    "100000",
        },
    }
    
    // 直接访问嵌入字段
    fmt.Printf("姓名: %s
", person.Name)
    fmt.Printf("街道: %s
", person.Street) // 直接访问
    fmt.Printf("城市: %s
", person.City)   // 直接访问
    
    // 也可以显式访问
    fmt.Printf("邮编: %s
", person.Address.Zip)
}

方法提升

// 基础结构体
type Engine struct {
    power int
}

func (e Engine) Start() {
    fmt.Printf("引擎启动,功率: %d
", e.power)
}

func (e Engine) Stop() {
    fmt.Println("引擎停止")
}

// 嵌入结构体
type Car struct {
    Brand string
    Engine // 嵌入Engine
}

// 使用示例
func main() {
    car := Car{
        Brand: "Toyota",
        Engine: Engine{power: 200},
    }
    
    // 直接调用嵌入结构体的方法
    car.Start() // 引擎启动,功率: 200
    car.Stop()  // 引擎停止
}

接口实现

隐式接口实现

// 定义接口
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 math.Pi * c.Radius * c.Radius
}

func (c Circle) Perimeter() float64 {
    return 2 * math.Pi * 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: 3},
    }
    
    for _, shape := range shapes {
        printShapeInfo(shape)
    }
}

结构体标签

结构体标签的使用

import (
    "encoding/json"
    "fmt"
)

type User struct {
    ID       int    `json:"id" db:"user_id"`
    Name     string `json:"name" db:"user_name"`
    Email    string `json:"email" db:"user_email"`
    Password string `json:"-" db:"user_password"` // 不序列化
}

func structTagsDemo() {
    user := User{
        ID:       1,
        Name:     "Alice",
        Email:    "alice@example.com",
        Password: "secret123",
    }
    
    // JSON序列化
    jsonData, err := json.Marshal(user)
    if err != nil {
        fmt.Println("序列化失败:", err)
        return
    }
    
    fmt.Printf("JSON: %s
", jsonData)
    // 输出: {"id":1,"name":"Alice","email":"alice@example.com"}
}

自定义标签处理

import (
    "reflect"
    "strings"
)

// 自定义标签处理函数
func processStructTags(v interface{}) {
    t := reflect.TypeOf(v)
    if t.Kind() == reflect.Ptr {
        t = t.Elem()
    }
    
    for i := 0; i < t.NumField(); i++ {
        field := t.Field(i)
        tag := field.Tag
        
        // 处理json标签
        if jsonTag := tag.Get("json"); jsonTag != "" {
            fmt.Printf("字段 %s 的JSON标签: %s
", field.Name, jsonTag)
        }
        
        // 处理db标签
        if dbTag := tag.Get("db"); dbTag != "" {
            fmt.Printf("字段 %s 的DB标签: %s
", field.Name, dbTag)
        }
    }
}

func main() {
    user := User{}
    processStructTags(user)
}

结构体的比较

可比较的结构体

type Point struct {
    X, Y int
}

func comparableStructs() {
    p1 := Point{1, 2}
    p2 := Point{1, 2}
    p3 := Point{2, 3}
    
    fmt.Println(p1 == p2) // true
    fmt.Println(p1 == p3) // false
    
    // 可以作为map的key
    points := make(map[Point]string)
    points[p1] = "第一个点"
    points[p2] = "第二个点"
    
    fmt.Println(points) // map[{1 2}:第二个点]
}

不可比较的结构体

type Person struct {
    Name string
    Age  int
    // 包含不可比较的字段
    Hobbies []string // 切片不可比较
}

func nonComparableStructs() {
    p1 := Person{Name: "Alice", Age: 30, Hobbies: []string{"reading"}}
    p2 := Person{Name: "Alice", Age: 30, Hobbies: []string{"reading"}}
    
    // 编译错误:无法比较包含切片的结构体
    // fmt.Println(p1 == p2)
    
    // 需要自定义比较函数
    fmt.Println(comparePersons(p1, p2))
}

func comparePersons(p1, p2 Person) bool {
    if p1.Name != p2.Name || p1.Age != p2.Age {
        return false
    }
    
    if len(p1.Hobbies) != len(p2.Hobbies) {
        return false
    }
    
    for i, hobby := range p1.Hobbies {
        if hobby != p2.Hobbies[i] {
            return false
        }
    }
    
    return true
}

结构体的内存布局

内存对齐

import "unsafe"

type AlignedStruct struct {
    a bool    // 1字节
    b int64   // 8字节
    c bool    // 1字节
}

type OptimizedStruct struct {
    b int64   // 8字节
    a bool    // 1字节
    c bool    // 1字节
}

func memoryLayout() {
    fmt.Printf("AlignedStruct大小: %d字节
", unsafe.Sizeof(AlignedStruct{}))    // 24字节
    fmt.Printf("OptimizedStruct大小: %d字节
", unsafe.Sizeof(OptimizedStruct{})) // 16字节
    
    // 获取字段偏移
    var s AlignedStruct
    fmt.Printf("字段a偏移: %d
", unsafe.Offsetof(s.a))
    fmt.Printf("字段b偏移: %d
", unsafe.Offsetof(s.b))
    fmt.Printf("字段c偏移: %d
", unsafe.Offsetof(s.c))
}

实战应用

构建器模式

type QueryBuilder struct {
    table   string
    columns []string
    where   []string
    orderBy string
    limit   int
}

func NewQueryBuilder(table string) *QueryBuilder {
    return &QueryBuilder{
        table:   table,
        columns: []string{},
        where:   []string{},
    }
}

func (qb *QueryBuilder) Select(columns ...string) *QueryBuilder {
    qb.columns = append(qb.columns, columns...)
    return qb
}

func (qb *QueryBuilder) Where(condition string) *QueryBuilder {
    qb.where = append(qb.where, condition)
    return qb
}

func (qb *QueryBuilder) OrderBy(column string) *QueryBuilder {
    qb.orderBy = column
    return qb
}

func (qb *QueryBuilder) Limit(n int) *QueryBuilder {
    qb.limit = n
    return qb
}

func (qb *QueryBuilder) Build() string {
    query := "SELECT "
    
    if len(qb.columns) == 0 {
        query += "*"
    } else {
        query += strings.Join(qb.columns, ", ")
    }
    
    query += " FROM " + qb.table
    
    if len(qb.where) > 0 {
        query += " WHERE " + strings.Join(qb.where, " AND ")
    }
    
    if qb.orderBy != "" {
        query += " ORDER BY " + qb.orderBy
    }
    
    if qb.limit > 0 {
        query += fmt.Sprintf(" LIMIT %d", qb.limit)
    }
    
    return query
}

// 使用示例
func main() {
    query := NewQueryBuilder("users").
        Select("id", "name", "email").
        Where("age > 18").
        Where("status = 'active'").
        OrderBy("created_at DESC").
        Limit(10).
        Build()
    
    fmt.Println(query)
    // 输出: SELECT id, name, email FROM users WHERE age > 18 AND status = 'active' ORDER BY created_at DESC LIMIT 10
}

单例模式

type Database struct {
    connection string
}

var (
    instance *Database
    once     sync.Once
)

func GetDatabase() *Database {
    once.Do(func() {
        instance = &Database{
            connection: "mysql://localhost:3306/mydb",
        }
    })
    return instance
}

func (db *Database) Query(sql string) {
    fmt.Printf("执行查询: %s
", sql)
}

写在最后

Go语言的结构体与方法设计体现了”组合优于继承”的思想。通过结构体,我们可以组织数据;通过方法,我们可以定义行为;通过嵌入,我们可以实现代码复用。

这种设计虽然简单,但功能强劲。它避免了传统面向对象语言中继承带来的复杂性,同时提供了足够的灵活性来构建复杂的系统。

作为Go开发者,理解结构体与方法的设计思想不仅有助于我们写出更好的代码,还能协助我们在设计系统时做出更好的架构决策。

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
东坡侍酒的头像 - 鹿快
评论 抢沙发

请登录后发表评论

    暂无评论内容