Go之路 - 7.go的结构体

一、结构体基础

1.1 结构体定义

go 复制代码
// 基本结构体定义
type Person struct {
    Name    string
    Age     int
    Email   string
    Address Address  // 嵌套结构体
}

// 匿名结构体
var user struct {
    ID   int
    Name string
}

1.2 结构体声明与初始化

go 复制代码
// 方法1:使用字段名初始化
p1 := Person{
    Name:  "张三",
    Age:   30,
    Email: "zhangsan@example.com",
}

// 方法2:按顺序初始化(必须包含所有字段)
p2 := Person{"李四", 25, "lisi@example.com", Address{}}

// 方法3:零值初始化
var p3 Person  // 所有字段为零值

// 方法4:使用new
p4 := new(Person)  // 返回指针
(*p4).Name = "王五"
p4.Name = "王五"    // 简写,Go自动解引用

二、结构体高级特性

2.1 嵌套与匿名嵌套

go 复制代码
type Address struct {
    City     string
    Street   string
    ZipCode  string
}

type Company struct {
    Name    string
    Address Address  // 具名嵌套
}

type Employee struct {
    Name    string
    Age     int
    Address          // 匿名嵌套(嵌入)
}

func main() {
    emp := Employee{
        Name: "张三",
        Age:  30,
        Address: Address{
            City:    "北京",
            Street:  "朝阳路",
            ZipCode: "100000",
        },
    }
    
    // 直接访问嵌入字段
    fmt.Println(emp.City)     // 北京
    fmt.Println(emp.Address.City)  // 同上
}

2.2 结构体标签(Tags)

go 复制代码
import "encoding/json"

type User struct {
    ID       int    `json:"id" db:"user_id"`
    Username string `json:"username" db:"username"`
    Password string `json:"-"`  // 不序列化
    Email    string `json:"email,omitempty"`  // 空值时不序列化
}

func main() {
    user := User{
        ID:       1,
        Username: "alice",
        Password: "secret",
    }
    
    // JSON 序列化
    data, _ := json.Marshal(user)
    fmt.Println(string(data))  // {"id":1,"username":"alice"}
}

2.3 结构体方法

go 复制代码
type Rectangle struct {
    Width  float64
    Height float64
}

// 值接收者方法(操作副本)
func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

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

// 方法调用
rect := Rectangle{Width: 10, Height: 5}
area := rect.Area()    // 50
rect.Scale(2)          // Width=20, Height=10

三、结构体组合与接口

3.1 组合实现"继承"

go 复制代码
type Animal struct {
    Name string
    Age  int
}

func (a *Animal) Speak() {
    fmt.Println("Animal speaks")
}

type Dog struct {
    Animal          // 嵌入Animal
    Breed   string
}

func (d *Dog) Bark() {
    fmt.Println("Woof!")
}

func main() {
    dog := Dog{
        Animal: Animal{Name: "Buddy", Age: 3},
        Breed:  "Golden Retriever",
    }
    
    dog.Speak()  // Animal speaks
    dog.Bark()   // Woof!
    fmt.Println(dog.Name)  // Buddy
}

3.2 结构体实现接口

go 复制代码
type Shape interface {
    Area() float64
    Perimeter() float64
}

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\n", s.Area(), s.Perimeter())
}

四、实用技巧与模式

4.1 工厂函数模式

go 复制代码
type Config struct {
    host     string
    port     int
    timeout  time.Duration
}

// 私有字段,使用工厂函数
func NewConfig(host string, port int) *Config {
    return &Config{
        host:    host,
        port:    port,
        timeout: 30 * time.Second,  // 默认值
    }
}

func (c *Config) WithTimeout(timeout time.Duration) *Config {
    c.timeout = timeout
    return c
}

4.2 结构体比较

go 复制代码
type Point struct {
    X, Y int
}

func main() {
    p1 := Point{1, 2}
    p2 := Point{1, 2}
    p3 := Point{2, 3}
    
    fmt.Println(p1 == p2)  // true
    fmt.Println(p1 == p3)  // false
    
    // 包含不可比较字段(如slice)的结构体不能比较
    type BadStruct struct {
        data []int
    }
    // b1 == b2  // 编译错误
}

4.3 空结构体

go 复制代码
// 零内存占用,用作标记或map的键
type empty struct{}

var signal = struct{}{}

// 用作Set的键
type Set map[string]struct{}

func (s Set) Add(key string) {
    s[key] = struct{}{}
}

func (s Set) Contains(key string) bool {
    _, ok := s[key]
    return ok
}

4.4 内存对齐与优化

go 复制代码
// 不良的内存布局
type BadLayout struct {
    b bool      // 1字节
    i int64     // 8字节
    s string    // 16字节
    b2 bool     // 1字节
} // 总大小:约32字节(包含填充)

// 优化的内存布局(按大小排序)
type GoodLayout struct {
    s string    // 16字节
    i int64     // 8字节
    b bool      // 1字节
    b2 bool     // 1字节
} // 总大小:约24字节

func main() {
    fmt.Println(unsafe.Sizeof(BadLayout{}))   // 32
    fmt.Println(unsafe.Sizeof(GoodLayout{}))  // 24
}

六、总结

  1. 使用工厂函数:提供清晰的对象创建方式
  2. 小写不可导出字段:通过方法控制访问
  3. 合理使用指针接收者
    • 需要修改接收者时
    • 结构体较大时避免复制
    • 保持一致性(要么全用指针,要么全用值)
  4. 利用结构体标签:简化序列化/反序列化
  5. 注意内存布局:对性能敏感的结构体进行字段重排
  6. 组合优于继承:使用嵌入实现代码复用
  7. 实现常用接口 :如 Stringer, error
相关推荐
源代码•宸8 小时前
分布式缓存-GO(分布式算法之一致性哈希、缓存对外服务化)
开发语言·经验分享·分布式·后端·算法·缓存·golang
云和数据.ChenGuang8 小时前
PHP-FPM返回的File not found.”的本质
开发语言·php·运维工程师·运维技术
It's now8 小时前
Spring AI 基础开发流程
java·人工智能·后端·spring
计算机毕设VX:Fegn08958 小时前
计算机毕业设计|基于springboot + vue图书商城系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·课程设计
R.lin9 小时前
Java 8日期时间API完全指南
java·开发语言·python
yangpipi-9 小时前
《C++并发编程实战》 第4章 并发操作的同步
开发语言·c++
火钳游侠9 小时前
java单行注释,多行注释,文档注释
java·开发语言
有趣的我9 小时前
C++ 多态介绍
开发语言·c++
fie888910 小时前
波束赋形MATLAB代码实现
开发语言·matlab