Files
golang/golang-learning/04-data-structures/04-structs.go
2025-08-24 01:15:18 +08:00

892 lines
21 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
04-structs.go - Go 语言结构体详解
学习目标:
1. 理解结构体的概念和作用
2. 掌握结构体的定义和使用
3. 学会结构体的初始化方式
4. 了解结构体的嵌入和组合
5. 掌握结构体的实际应用场景
知识点:
- 结构体的定义和特性
- 结构体的初始化方式
- 结构体字段的访问和修改
- 结构体的方法
- 结构体的嵌入和组合
- 结构体的标签
- 结构体的比较和拷贝
*/
package main
import (
"fmt"
)
func main() {
fmt.Println("=== Go 语言结构体详解 ===\n")
// 演示结构体的基本概念
demonstrateBasicStructs()
// 演示结构体的初始化
demonstrateStructInitialization()
// 演示结构体的方法
demonstrateStructMethods()
// 演示结构体的嵌入
demonstrateStructEmbedding()
// 演示结构体的标签
demonstrateStructTags()
// 演示结构体的高级特性
demonstrateAdvancedStructFeatures()
// 演示结构体的实际应用
demonstratePracticalApplications()
}
// demonstrateBasicStructs 演示结构体的基本概念
func demonstrateBasicStructs() {
fmt.Println("1. 结构体的基本概念:")
// 结构体的基本特性
fmt.Printf(" 结构体的基本特性:\n")
fmt.Printf(" - 用户自定义的复合数据类型\n")
fmt.Printf(" - 将相关数据组织在一起\n")
fmt.Printf(" - 值类型,赋值和传参会拷贝\n")
fmt.Printf(" - 可以有方法\n")
fmt.Printf(" - 支持嵌入和组合\n")
// 基本结构体示例
fmt.Printf(" 基本结构体示例:\n")
// 创建结构体实例
var p Person
fmt.Printf(" 零值结构体: %+v\n", p)
// 设置字段值
p.Name = "Alice"
p.Age = 25
p.Email = "alice@example.com"
fmt.Printf(" 设置字段后: %+v\n", p)
// 访问字段
fmt.Printf(" 姓名: %s\n", p.Name)
fmt.Printf(" 年龄: %d\n", p.Age)
fmt.Printf(" 邮箱: %s\n", p.Email)
// 结构体比较
fmt.Printf(" 结构体比较:\n")
p1 := Person{Name: "Bob", Age: 30, Email: "bob@example.com"}
p2 := Person{Name: "Bob", Age: 30, Email: "bob@example.com"}
p3 := Person{Name: "Charlie", Age: 25, Email: "charlie@example.com"}
fmt.Printf(" p1 == p2: %t\n", p1 == p2)
fmt.Printf(" p1 == p3: %t\n", p1 == p3)
// 结构体作为值类型
fmt.Printf(" 结构体作为值类型:\n")
original := Person{Name: "David", Age: 35, Email: "david@example.com"}
copied := original
fmt.Printf(" 原结构体: %+v\n", original)
fmt.Printf(" 拷贝结构体: %+v\n", copied)
// 修改拷贝不影响原结构体
copied.Age = 40
fmt.Printf(" 修改拷贝后:\n")
fmt.Printf(" 原结构体: %+v\n", original)
fmt.Printf(" 拷贝结构体: %+v\n", copied)
fmt.Println()
}
// demonstrateStructInitialization 演示结构体的初始化
func demonstrateStructInitialization() {
fmt.Println("2. 结构体的初始化:")
// 方式1: 零值初始化
fmt.Printf(" 方式1 - 零值初始化:\n")
var p1 Person
fmt.Printf(" var p1 Person: %+v\n", p1)
// 方式2: 字段名初始化
fmt.Printf(" 方式2 - 字段名初始化:\n")
p2 := Person{
Name: "Alice",
Age: 25,
Email: "alice@example.com",
}
fmt.Printf(" 字段名初始化: %+v\n", p2)
// 方式3: 位置初始化(不推荐)
fmt.Printf(" 方式3 - 位置初始化:\n")
p3 := Person{"Bob", 30, "bob@example.com"}
fmt.Printf(" 位置初始化: %+v\n", p3)
// 方式4: 部分初始化
fmt.Printf(" 方式4 - 部分初始化:\n")
p4 := Person{
Name: "Charlie",
Age: 35,
// Email 使用零值
}
fmt.Printf(" 部分初始化: %+v\n", p4)
// 方式5: 使用 new 函数
fmt.Printf(" 方式5 - 使用 new 函数:\n")
p5 := new(Person)
p5.Name = "David"
p5.Age = 40
fmt.Printf(" new(Person): %+v\n", *p5)
// 方式6: 结构体字面量的地址
fmt.Printf(" 方式6 - 结构体字面量的地址:\n")
p6 := &Person{
Name: "Eve",
Age: 28,
Email: "eve@example.com",
}
fmt.Printf(" &Person{...}: %+v\n", *p6)
// 复杂结构体初始化
fmt.Printf(" 复杂结构体初始化:\n")
addr := Address{
Street: "123 Main St",
City: "New York",
Country: "USA",
ZipCode: "10001",
}
employee := Employee{
Person: Person{
Name: "Frank",
Age: 32,
Email: "frank@company.com",
},
ID: 1001,
Position: "Software Engineer",
Salary: 75000,
Address: addr,
}
fmt.Printf(" 复杂结构体: %+v\n", employee)
// 匿名结构体
fmt.Printf(" 匿名结构体:\n")
point := struct {
X, Y int
}{
X: 10,
Y: 20,
}
fmt.Printf(" 匿名结构体: %+v\n", point)
fmt.Println()
}//
demonstrateStructMethods 演示结构体的方法
func demonstrateStructMethods() {
fmt.Println("3. 结构体的方法:")
// 创建结构体实例
fmt.Printf(" 结构体方法调用:\n")
rect := Rectangle{Width: 10, Height: 5}
fmt.Printf(" 矩形: %+v\n", rect)
fmt.Printf(" 面积: %.2f\n", rect.Area())
fmt.Printf(" 周长: %.2f\n", rect.Perimeter())
// 值接收者 vs 指针接收者
fmt.Printf(" 值接收者 vs 指针接收者:\n")
// 值接收者方法
fmt.Printf(" 调用值接收者方法:\n")
info := rect.String()
fmt.Printf(" String(): %s\n", info)
// 指针接收者方法
fmt.Printf(" 调用指针接收者方法:\n")
fmt.Printf(" 修改前: %+v\n", rect)
rect.Scale(2.0)
fmt.Printf(" Scale(2.0)后: %+v\n", rect)
// 方法链调用
fmt.Printf(" 方法链调用:\n")
rect2 := Rectangle{Width: 3, Height: 4}
fmt.Printf(" 原矩形: %+v\n", rect2)
result := rect2.SetWidth(6).SetHeight(8)
fmt.Printf(" 链式调用后: %+v\n", *result)
// 结构体方法作为函数值
fmt.Printf(" 结构体方法作为函数值:\n")
circle := Circle{Radius: 5}
areaFunc := circle.Area
circumferenceFunc := circle.Circumference
fmt.Printf(" 圆形: %+v\n", circle)
fmt.Printf(" 方法值调用 - 面积: %.2f\n", areaFunc())
fmt.Printf(" 方法值调用 - 周长: %.2f\n", circumferenceFunc())
fmt.Println()
}
// demonstrateStructEmbedding 演示结构体的嵌入
func demonstrateStructEmbedding() {
fmt.Println("4. 结构体的嵌入:")
// 具名嵌入
fmt.Printf(" 具名嵌入:\n")
emp := Employee{
Person: Person{
Name: "Alice",
Age: 30,
Email: "alice@company.com",
},
ID: 1001,
Position: "Manager",
Salary: 80000,
}
fmt.Printf(" 员工信息: %+v\n", emp)
fmt.Printf(" 访问嵌入字段: %s, %d\n", emp.Person.Name, emp.Person.Age)
// 匿名嵌入
fmt.Printf(" 匿名嵌入:\n")
manager := Manager{
Person: Person{
Name: "Bob",
Age: 35,
Email: "bob@company.com",
},
Department: "Engineering",
TeamSize: 10,
}
fmt.Printf(" 经理信息: %+v\n", manager)
// 直接访问嵌入字段
fmt.Printf(" 直接访问嵌入字段:\n")
fmt.Printf(" 姓名: %s\n", manager.Name) // 等同于 manager.Person.Name
fmt.Printf(" 年龄: %d\n", manager.Age) // 等同于 manager.Person.Age
fmt.Printf(" 邮箱: %s\n", manager.Email) // 等同于 manager.Person.Email
// 调用嵌入类型的方法
fmt.Printf(" 调用嵌入类型的方法:\n")
info := manager.GetInfo() // Person 的方法
fmt.Printf(" GetInfo(): %s\n", info)
// 方法重写
fmt.Printf(" 方法重写:\n")
student := Student{
Person: Person{
Name: "Charlie",
Age: 20,
Email: "charlie@university.edu",
},
StudentID: "S12345",
Major: "Computer Science",
GPA: 3.8,
}
fmt.Printf(" 学生信息: %+v\n", student)
// Student 重写了 GetInfo 方法
studentInfo := student.GetInfo()
fmt.Printf(" Student.GetInfo(): %s\n", studentInfo)
// 仍然可以访问原始方法
personInfo := student.Person.GetInfo()
fmt.Printf(" Person.GetInfo(): %s\n", personInfo)
// 多重嵌入
fmt.Printf(" 多重嵌入:\n")
contact := ContactInfo{
Phone: "123-456-7890",
Address: "123 Main St",
}
fullEmployee := FullEmployee{
Person: Person{Name: "David", Age: 28, Email: "david@company.com"},
Employee: Employee{ID: 1002, Position: "Developer", Salary: 70000},
ContactInfo: contact,
}
fmt.Printf(" 完整员工信息: %+v\n", fullEmployee)
fmt.Printf(" 访问各层字段:\n")
fmt.Printf(" 姓名: %s\n", fullEmployee.Person.Name)
fmt.Printf(" 职位: %s\n", fullEmployee.Employee.Position)
fmt.Printf(" 电话: %s\n", fullEmployee.ContactInfo.Phone)
fmt.Println()
}
// demonstrateStructTags 演示结构体的标签
func demonstrateStructTags() {
fmt.Println("5. 结构体的标签:")
fmt.Printf(" 结构体标签用于元数据,常用于序列化、验证等\n")
// 创建带标签的结构体实例
user := User{
ID: 1,
Username: "alice",
Email: "alice@example.com",
FullName: "Alice Smith",
IsActive: true,
CreatedAt: time.Now(),
}
fmt.Printf(" 用户信息: %+v\n", user)
// 使用反射读取标签
fmt.Printf(" 使用反射读取标签:\n")
userType := reflect.TypeOf(user)
for i := 0; i < userType.NumField(); i++ {
field := userType.Field(i)
jsonTag := field.Tag.Get("json")
dbTag := field.Tag.Get("db")
validateTag := field.Tag.Get("validate")
fmt.Printf(" 字段 %s:\n", field.Name)
if jsonTag != "" {
fmt.Printf(" json: %s\n", jsonTag)
}
if dbTag != "" {
fmt.Printf(" db: %s\n", dbTag)
}
if validateTag != "" {
fmt.Printf(" validate: %s\n", validateTag)
}
}
// 标签的实际应用
fmt.Printf(" 标签的实际应用:\n")
fmt.Printf(" - JSON 序列化/反序列化\n")
fmt.Printf(" - 数据库 ORM 映射\n")
fmt.Printf(" - 数据验证\n")
fmt.Printf(" - 配置文件解析\n")
fmt.Printf(" - API 文档生成\n")
fmt.Println()
}
// demonstrateAdvancedStructFeatures 演示结构体的高级特性
func demonstrateAdvancedStructFeatures() {
fmt.Println("6. 结构体的高级特性:")
// 结构体作为映射的值
fmt.Printf(" 结构体作为映射的值:\n")
users := map[string]Person{
"alice": {Name: "Alice", Age: 25, Email: "alice@example.com"},
"bob": {Name: "Bob", Age: 30, Email: "bob@example.com"},
}
fmt.Printf(" 用户映射: %+v\n", users)
// 结构体切片
fmt.Printf(" 结构体切片:\n")
people := []Person{
{Name: "Alice", Age: 25, Email: "alice@example.com"},
{Name: "Bob", Age: 30, Email: "bob@example.com"},
{Name: "Charlie", Age: 35, Email: "charlie@example.com"},
}
fmt.Printf(" 人员列表:\n")
for i, person := range people {
fmt.Printf(" %d: %s (%d岁)\n", i+1, person.Name, person.Age)
}
// 结构体指针切片
fmt.Printf(" 结构体指针切片:\n")
var personPtrs []*Person
for i := range people {
personPtrs = append(personPtrs, &people[i])
}
// 修改通过指针
personPtrs[0].Age = 26
fmt.Printf(" 修改后的第一个人: %+v\n", people[0])
// 空结构体
fmt.Printf(" 空结构体:\n")
type Empty struct{}
var empty Empty
fmt.Printf(" 空结构体大小: %d 字节\n", reflect.TypeOf(empty).Size())
fmt.Printf(" 空结构体常用于信号传递和集合实现\n")
// 使用空结构体实现集合
set := make(map[string]struct{})
set["item1"] = struct{}{}
set["item2"] = struct{}{}
fmt.Printf(" 集合: %v\n", getMapKeys(set))
// 结构体的内存对齐
fmt.Printf(" 结构体的内存对齐:\n")
type Aligned struct {
a bool // 1 byte
b int64 // 8 bytes
c bool // 1 byte
}
type Optimized struct {
b int64 // 8 bytes
a bool // 1 byte
c bool // 1 byte
}
fmt.Printf(" 未优化结构体大小: %d 字节\n", reflect.TypeOf(Aligned{}).Size())
fmt.Printf(" 优化后结构体大小: %d 字节\n", reflect.TypeOf(Optimized{}).Size())
fmt.Println()
}
// demonstratePracticalApplications 演示结构体的实际应用
func demonstratePracticalApplications() {
fmt.Println("7. 结构体的实际应用:")
// 应用1: 配置管理
fmt.Printf(" 应用1 - 配置管理:\n")
config := Config{
Server: ServerConfig{
Host: "localhost",
Port: 8080,
SSL: false,
},
Database: DatabaseConfig{
Host: "localhost",
Port: 5432,
Username: "admin",
Password: "secret",
Database: "myapp",
},
Cache: CacheConfig{
Enabled: true,
TTL: 300,
MaxSize: 1000,
},
}
fmt.Printf(" 应用配置: %+v\n", config)
fmt.Printf(" 服务器地址: %s:%d\n", config.Server.Host, config.Server.Port)
fmt.Printf(" 数据库连接: %s@%s:%d/%s\n",
config.Database.Username, config.Database.Host,
config.Database.Port, config.Database.Database)
// 应用2: HTTP 请求/响应
fmt.Printf(" 应用2 - HTTP 请求/响应:\n")
request := HTTPRequest{
Method: "POST",
URL: "/api/users",
Headers: map[string]string{
"Content-Type": "application/json",
"Authorization": "Bearer token123",
},
Body: `{"name": "Alice", "email": "alice@example.com"}`,
}
response := HTTPResponse{
StatusCode: 201,
Headers: map[string]string{
"Content-Type": "application/json",
},
Body: `{"id": 1, "name": "Alice", "email": "alice@example.com"}`,
}
fmt.Printf(" HTTP 请求: %+v\n", request)
fmt.Printf(" HTTP 响应: %+v\n", response)
// 应用3: 数据传输对象 (DTO)
fmt.Printf(" 应用3 - 数据传输对象:\n")
userDTO := UserDTO{
ID: 1,
Username: "alice",
Profile: ProfileDTO{
FirstName: "Alice",
LastName: "Smith",
Bio: "Software Developer",
},
Settings: SettingsDTO{
Theme: "dark",
Notifications: true,
Language: "en",
},
}
fmt.Printf(" 用户 DTO: %+v\n", userDTO)
// 应用4: 事件系统
fmt.Printf(" 应用4 - 事件系统:\n")
events := []Event{
{
ID: 1,
Type: "user.created",
Timestamp: time.Now(),
Data: map[string]interface{}{
"user_id": 123,
"email": "user@example.com",
},
},
{
ID: 2,
Type: "order.placed",
Timestamp: time.Now(),
Data: map[string]interface{}{
"order_id": 456,
"amount": 99.99,
},
},
}
fmt.Printf(" 事件列表:\n")
for _, event := range events {
fmt.Printf(" 事件 %d: %s (时间: %s)\n",
event.ID, event.Type, event.Timestamp.Format("15:04:05"))
fmt.Printf(" 数据: %+v\n", event.Data)
}
// 应用5: 状态机
fmt.Printf(" 应用5 - 状态机:\n")
fsm := StateMachine{
CurrentState: "idle",
States: map[string]State{
"idle": {
Name: "idle",
Transitions: map[string]string{
"start": "running",
},
},
"running": {
Name: "running",
Transitions: map[string]string{
"pause": "paused",
"stop": "idle",
},
},
"paused": {
Name: "paused",
Transitions: map[string]string{
"resume": "running",
"stop": "idle",
},
},
},
}
fmt.Printf(" 状态机当前状态: %s\n", fsm.CurrentState)
// 状态转换
if newState, ok := fsm.States[fsm.CurrentState].Transitions["start"]; ok {
fsm.CurrentState = newState
fmt.Printf(" 执行 'start' 转换后状态: %s\n", fsm.CurrentState)
}
fmt.Println()
}// ===
======= 结构体定义 ==========
// 基本结构体
type Person struct {
Name string
Age int
Email string
}
// Person 的方法
func (p Person) GetInfo() string {
return fmt.Sprintf("%s (%d岁) - %s", p.Name, p.Age, p.Email)
}
func (p Person) IsAdult() bool {
return p.Age >= 18
}
// 地址结构体
type Address struct {
Street string
City string
Country string
ZipCode string
}
// 员工结构体(具名嵌入)
type Employee struct {
Person Person // 具名嵌入
ID int
Position string
Salary float64
Address Address
}
// 几何图形结构体
type Rectangle struct {
Width float64
Height float64
}
// Rectangle 的方法
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
func (r Rectangle) Perimeter() float64 {
return 2 * (r.Width + r.Height)
}
func (r Rectangle) String() string {
return fmt.Sprintf("Rectangle(%.1f x %.1f)", r.Width, r.Height)
}
// 指针接收者方法
func (r *Rectangle) Scale(factor float64) {
r.Width *= factor
r.Height *= factor
}
// 方法链
func (r *Rectangle) SetWidth(width float64) *Rectangle {
r.Width = width
return r
}
func (r *Rectangle) SetHeight(height float64) *Rectangle {
r.Height = height
return r
}
// 圆形结构体
type Circle struct {
Radius float64
}
func (c Circle) Area() float64 {
return 3.14159 * c.Radius * c.Radius
}
func (c Circle) Circumference() float64 {
return 2 * 3.14159 * c.Radius
}
// 经理结构体(匿名嵌入)
type Manager struct {
Person // 匿名嵌入
Department string
TeamSize int
}
// 学生结构体(方法重写)
type Student struct {
Person
StudentID string
Major string
GPA float64
}
// 重写 Person 的 GetInfo 方法
func (s Student) GetInfo() string {
return fmt.Sprintf("学生 %s (%d岁) - %s专业, 学号: %s, GPA: %.1f",
s.Name, s.Age, s.Major, s.StudentID, s.GPA)
}
// 联系信息结构体
type ContactInfo struct {
Phone string
Address string
}
// 完整员工结构体(多重嵌入)
type FullEmployee struct {
Person
Employee
ContactInfo
}
// 带标签的结构体
type User struct {
ID int `json:"id" db:"id" validate:"required"`
Username string `json:"username" db:"username" validate:"required,min=3,max=20"`
Email string `json:"email" db:"email" validate:"required,email"`
FullName string `json:"full_name" db:"full_name"`
IsActive bool `json:"is_active" db:"is_active"`
CreatedAt time.Time `json:"created_at" db:"created_at"`
}
// 配置结构体
type Config struct {
Server ServerConfig
Database DatabaseConfig
Cache CacheConfig
}
type ServerConfig struct {
Host string
Port int
SSL bool
}
type DatabaseConfig struct {
Host string
Port int
Username string
Password string
Database string
}
type CacheConfig struct {
Enabled bool
TTL int
MaxSize int
}
// HTTP 请求/响应结构体
type HTTPRequest struct {
Method string
URL string
Headers map[string]string
Body string
}
type HTTPResponse struct {
StatusCode int
Headers map[string]string
Body string
}
// 数据传输对象
type UserDTO struct {
ID int `json:"id"`
Username string `json:"username"`
Profile ProfileDTO `json:"profile"`
Settings SettingsDTO `json:"settings"`
}
type ProfileDTO struct {
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Bio string `json:"bio"`
}
type SettingsDTO struct {
Theme string `json:"theme"`
Notifications bool `json:"notifications"`
Language string `json:"language"`
}
// 事件结构体
type Event struct {
ID int `json:"id"`
Type string `json:"type"`
Timestamp time.Time `json:"timestamp"`
Data map[string]interface{} `json:"data"`
}
// 状态机结构体
type StateMachine struct {
CurrentState string
States map[string]State
}
type State struct {
Name string
Transitions map[string]string
}
// ========== 辅助函数 ==========
// 获取映射的键
func getMapKeys(m map[string]struct{}) []string {
var keys []string
for key := range m {
keys = append(keys, key)
}
return keys
}
/*
运行这个程序:
go run 04-structs.go
学习要点:
1. 结构体是用户自定义的复合数据类型
2. 结构体是值类型,赋值和传参会拷贝整个结构体
3. 结构体可以有方法,支持面向对象编程
4. 结构体支持嵌入和组合,实现代码复用
5. 结构体标签用于元数据,常用于序列化和验证
结构体的特性:
1. 类型安全:编译时检查字段类型
2. 内存效率:字段在内存中连续存储
3. 可比较性:所有字段可比较时结构体可比较
4. 零值:所有字段都为零值的结构体
5. 方法:可以定义方法操作结构体
初始化方式:
1. 零值初始化var s Struct
2. 字段名初始化Struct{Field: value}
3. 位置初始化Struct{value1, value2}
4. 部分初始化Struct{Field1: value}
5. 指针初始化:&Struct{} 或 new(Struct)
结构体嵌入:
1. 具名嵌入:显式字段名
2. 匿名嵌入:直接访问嵌入字段
3. 方法继承:自动获得嵌入类型的方法
4. 方法重写:可以重写嵌入类型的方法
结构体标签:
1. 元数据:为字段提供额外信息
2. 反射访问:通过反射读取标签
3. 常见用途JSON、数据库、验证
4. 格式:`key:"value" key2:"value2"`
最佳实践:
1. 字段名使用驼峰命名
2. 导出字段首字母大写
3. 合理组织字段顺序(内存对齐)
4. 使用指针接收者修改结构体
5. 适当使用嵌入实现代码复用
常见应用场景:
1. 数据模型和实体
2. 配置管理
3. API 请求/响应
4. 事件和消息
5. 状态管理
6. 数据传输对象
注意事项:
1. 结构体是值类型,大结构体传参考虑性能
2. 嵌入字段的方法可能被重写
3. 结构体比较要求所有字段可比较
4. 注意内存对齐对结构体大小的影响
5. 合理使用标签,避免过度复杂化
内存优化:
1. 字段排序:大字段在前,小字段在后
2. 使用指针:大结构体考虑使用指针
3. 空结构体:零内存占用,适合信号传递
4. 字段对齐:了解内存对齐规则
*/