结构体 (Struct)

什么是结构体

enter image description here体是一种自定义的数据类型,用于将不同类型的数据组合在一起。它类似于其他语言中的类,但更简单

结构体的定义和初始化

1. 定义结构体

type Person struct {
    Name string
    Age  int
    City string
}

2. 创建结构体实例

// 方法 1:按字段顺序初始化
person1 := Person{"张三", 25, "北京"}

// 方法 2:指定字段名初始化
person2 := Person{
    Name: "李四",
    Age:  30,
    City: "上海",
}

// 方法 3:零值初始化后赋值
var person3 Person
person3.Name = "王五"
person3.Age = 28
person3.City = "广州"

// 方法 4:使用 new 函数
person4 := new(Person)
person4.Name = "赵六"

结构体的基本操作

1. 访问和修改字段

person := Person{Name: "张三", Age: 25, City: "北京"}
fmt.Println(person.Name)          // 访问字段
person.Age = 26                   // 修改字段

2. 结构体指针

person := &Person{Name: "张三", Age: 25, City: "北京"}
fmt.Println(person.Name)          // Go 自动解引用
(*person).Age = 26                // 显式解引用

3. 匿名字段

type Employee struct {
    Person                        // 匿名字段(嵌入)
    ID     int
    Salary float64
}

emp := Employee{
    Person: Person{Name: "张三", Age: 25, City: "北京"},
    ID:     1001,
    Salary: 8000.0,
}

fmt.Println(emp.Name)             // 可以直接访问嵌入字段

结构体方法

1. 值接收器方法

func (p Person) GetInfo() string {
    return fmt.Sprintf("姓名: %s, 年龄: %d, 城市: %s", p.Name, p.Age, p.City)
}

2. 指针接收器方法

func (p *Person) SetAge(age int) {
    p.Age = age
}

func (p *Person) HaveBirthday() {
    p.Age++
}

结构体标签

结构体标签常用于 JSON 序列化、数据验证等场景:

type User struct {
    ID       int    `json:"id" db:"user_id"`
    Username string `json:"username" db:"username"`
    Email    string `json:"email" db:"email"`
    Password string `json:"-" db:"password"`  // JSON 中忽略此字段
}

实际应用示例

package main

import (
    "encoding/json"
    "fmt"
)

// 定义学生结构体
type Student struct {
    ID     int      `json:"id"`
    Name   string   `json:"name"`
    Age    int      `json:"age"`
    Scores []int    `json:"scores"`
}

// 计算平均分的方法
func (s Student) Average() float64 {
    if len(s.Scores) == 0 {
        return 0
    }

    total := 0
    for _, score := range s.Scores {
        total += score
    }
    return float64(total) / float64(len(s.Scores))
}

// 添加成绩的方法
func (s *Student) AddScore(score int) {
    s.Scores = append(s.Scores, score)
}

// 获取学生信息的方法
func (s Student) GetInfo() string {
    return fmt.Sprintf("学号: %d, 姓名: %s, 年龄: %d, 平均分: %.2f",
        s.ID, s.Name, s.Age, s.Average())
}

func main() {
    // 创建学生
    student := Student{
        ID:     1001,
        Name:   "张三",
        Age:    20,
        Scores: []int{85, 92, 78, 96},
    }

    // 使用方法
    fmt.Println(student.GetInfo())

    // 添加新成绩
    student.AddScore(88)
    fmt.Printf("添加新成绩后的平均分: %.2f\n", student.Average())

    // JSON 序列化
    jsonData, err := json.Marshal(student)
    if err != nil {
        fmt.Printf("JSON 序列化错误: %v\n", err)
        return
    }
    fmt.Printf("JSON 数据: %s\n", jsonData)

    // JSON 反序列化
    var newStudent Student
    err = json.Unmarshal(jsonData, &newStudent)
    if err != nil {
        fmt.Printf("JSON 反序列化错误: %v\n", err)
        return
    }
    fmt.Printf("反序列化后: %s\n", newStudent.GetInfo())
}

结构体最佳实践

  1. 字段命名:使用驼峰命名法,大写字母开头的字段可被包外访问

  2. 零值可用:设计结构体时考虑零值是否有意义

  3. 嵌入vs组合:优先使用组合而不是嵌入,除非确实需要继承行为

  4. 方法接收器

    • 如果方法需要修改结构体,使用指针接收器

    • 如果结构体很大,使用指针接收器以避免复制

    • 保持一致性:如果有些方法使用指针接收器,其他方法也应该使用


总结

Go 语言的三种基本数据结构各有特点:

  • 切片:动态数组,提供灵活的长度管理

  • 映射:键值对存储,快速查找和访问

  • 结构体:自定义类型,组织相关数据和行为

这些数据结构是 Go 程序的基础构建块,理解和熟练使用它们对于编写高效的 Go 程序至关重要。

结构体 (Struct)

1. 结构体基础

结构体定义和初始化

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

// 结构体初始化方式
func structInitialization() {
    // 方式1: 字段名初始化
    p1 := Person{
        Name: "Alice",
        Age:  25,
        City: "New York",
    }
    
    // 方式2: 按顺序初始化
    p2 := Person{"Bob", 30, "London"}
    
    // 方式3: 部分初始化
    p3 := Person{Name: "Charlie", Age: 28}
    
    // 方式4: 使用 new
    p4 := new(Person)
    p4.Name = "David"
    p4.Age = 35
}

结构体方法

// 值接收者方法
func (p Person) GetInfo() string {
    return fmt.Sprintf("Name: %s, Age: %d, City: %s", p.Name, p.Age, p.City)
}

// 指针接收者方法
func (p *Person) SetAge(age int) {
    p.Age = age
}

func (p *Person) HaveBirthday() {
    p.Age++
}

// 使用示例
func main() {
    person := Person{Name: "Alice", Age: 25, City: "New York"}
    
    // 调用值接收者方法
    fmt.Println(person.GetInfo())
    
    // 调用指针接收者方法
    person.SetAge(26)
    person.HaveBirthday()
    fmt.Printf("New age: %d\n", person.Age) // 输出: 27
}

2. 结构体高级特性

嵌入结构体

type Address struct {
    Street  string
    City    string
    Country string
}

type Employee struct {
    Person  // 嵌入 Person 结构体
    Address // 嵌入 Address 结构体
    Salary  float64
    Company string
}

func embeddedStructs() {
    emp := Employee{
        Person: Person{
            Name: "John",
            Age:  30,
        },
        Address: Address{
            Street:  "123 Main St",
            City:    "Boston",
            Country: "USA",
        },
        Salary:  50000,
        Company: "TechCorp",
    }
    
    // 可以直接访问嵌入结构体的字段
    fmt.Println(emp.Name)    // 来自 Person
    fmt.Println(emp.City)    // 来自 Address
    fmt.Println(emp.Salary)  // Employee 自己的字段
}

结构体标签

import (
    "encoding/json"
    "fmt"
)

type User struct {
    ID       int    `json:"id"`
    Username string `json:"username"`
    Email    string `json:"email,omitempty"`
    Password string `json:"-"` // 不会被序列化
}

func structTags() {
    user := User{
        ID:       1,
        Username: "alice",
        Email:    "alice@example.com",
        Password: "secret123",
    }
    
    // JSON 序列化
    jsonData, _ := json.Marshal(user)
    fmt.Println(string(jsonData))
    // 输出: {"id":1,"username":"alice","email":"alice@example.com"}
}

3. 实际应用示例

学生管理系统

type Student struct {
    ID      int
    Name    string
    Grades  map[string]int
    Address Address
}

func (s *Student) AddGrade(subject string, grade int) {
    if s.Grades == nil {
        s.Grades = make(map[string]int)
    }
    s.Grades[subject] = grade
}

func (s Student) GetAverageGrade() float64 {
    if len(s.Grades) == 0 {
        return 0
    }
    
    total := 0
    for _, grade := range s.Grades {
        total += grade
    }
    return float64(total) / float64(len(s.Grades))
}

func (s Student) GetGradeReport() string {
    var report string
    report += fmt.Sprintf("Student: %s (ID: %d)\n", s.Name, s.ID)
    report += "Grades:\n"
    
    for subject, grade := range s.Grades {
        report += fmt.Sprintf("  %s: %d\n", subject, grade)
    }
    
    report += fmt.Sprintf("Average: %.2f\n", s.GetAverageGrade())
    return report
}

// 使用示例
func studentManagementExample() {
    student := Student{
        ID:   1,
        Name: "Alice Johnson",
        Address: Address{
            Street:  "456 Oak Ave",
            City:    "Boston",
            Country: "USA",
        },
    }
    
    student.AddGrade("Math", 95)
    student.AddGrade("English", 87)
    student.AddGrade("Science", 92)
    
    fmt.Println(student.GetGradeReport())
}
作者:admin  创建时间:2025-09-23 22:24
最后编辑:admin  更新时间:2025-09-24 00:14