Skip to content

结构体详解 - Golang基础面试题

结构体是Go语言中用户定义的类型,它将零个或多个任意类型的值聚合成一个实体。本章深入探讨结构体的各种特性和最佳实践。

📋 重点面试题

面试题 1:结构体的定义和初始化

难度级别:⭐⭐⭐
考察范围:基础语法/内存模型
技术标签struct initialization zero value memory layout

问题分析

结构体的定义和初始化方式多样,理解不同初始化方式的特点和内存布局对于掌握Go语言至关重要。

详细解答

1. 结构体的基本定义和初始化

点击查看完整代码实现
点击查看完整代码实现
go
package main

import (
    "fmt"
    "unsafe"
)

// 基本结构体定义
type Person struct {
    Name    string
    Age     int
    Email   string
    Height  float64
    IsActive bool
}

// 带标签的结构体
type User struct {
    ID       int    `json:"id" db:"user_id"`
    Name     string `json:"name" db:"username"`
    Email    string `json:"email" db:"email"`
    Password string `json:"-" db:"password"`      // json忽略
    CreateAt int64  `json:"create_at,omitempty"` // 空值时忽略
}

func demonstrateStructBasics() {
    // 1. 零值初始化
    var p1 Person
    fmt.Printf("零值初始化: %+v\n", p1)
    // 输出: {Name: Age:0 Email: Height:0 IsActive:false}
    
    // 2. 字面量初始化(按字段顺序)
    p2 := Person{"Alice", 30, "alice@example.com", 165.5, true}
    fmt.Printf("顺序初始化: %+v\n", p2)
    
    // 3. 字面量初始化(指定字段名)- 推荐方式
    p3 := Person{
        Name:     "Bob",
        Age:      25,
        Email:    "bob@example.com",
        Height:   180.0,
        IsActive: true,
    }
    fmt.Printf("字段名初始化: %+v\n", p3)
    
    // 4. 部分字段初始化
    p4 := Person{
        Name: "Charlie",
        Age:  35,
        // 其他字段使用零值
    }
    fmt.Printf("部分初始化: %+v\n", p4)
    
    // 5. 指针初始化
    p5 := &Person{
        Name:   "Diana",
        Age:    28,
        Email:  "diana@example.com",
        Height: 170.0,
    }
    fmt.Printf("指针初始化: %+v\n", *p5)
    
    // 6. new函数初始化
    p6 := new(Person)
    p6.Name = "Eve"
    p6.Age = 32
    fmt.Printf("new初始化: %+v\n", *p6)
}

:::

2. 结构体的内存布局

点击查看完整代码实现
点击查看完整代码实现
点击查看完整代码实现
go
func demonstrateMemoryLayout() {
    type SmallStruct struct {
        A int8   // 1 byte
        B int32  // 4 bytes
        C int8   // 1 byte
    }
    
    type OptimizedStruct struct {
        A int8   // 1 byte
        C int8   // 1 byte (紧挨着A)
        B int32  // 4 bytes
    }
    
    // 查看结构体大小
    fmt.Printf("SmallStruct 大小: %d bytes\n", unsafe.Sizeof(SmallStruct{}))     // 12 bytes (由于内存对齐)
    fmt.Printf("OptimizedStruct 大小: %d bytes\n", unsafe.Sizeof(OptimizedStruct{})) // 8 bytes
    
    // 查看字段偏移量
    s := SmallStruct{}
    fmt.Printf("SmallStruct.A 偏移: %d\n", unsafe.Offsetof(s.A)) // 0
    fmt.Printf("SmallStruct.B 偏移: %d\n", unsafe.Offsetof(s.B)) // 4
    fmt.Printf("SmallStruct.C 偏移: %d\n", unsafe.Offsetof(s.C)) // 8
    
    o := OptimizedStruct{}
    fmt.Printf("OptimizedStruct.A 偏移: %d\n", unsafe.Offsetof(o.A)) // 0
    fmt.Printf("OptimizedStruct.C 偏移: %d\n", unsafe.Offsetof(o.C)) // 1
    fmt.Printf("OptimizedStruct.B 偏移: %d\n", unsafe.Offsetof(o.B)) // 4
    
    // 内存对齐规则示例
    type AlignmentExample struct {
        A bool    // 1 byte
        B int64   // 8 bytes,需要8字节对齐
        C int32   // 4 bytes
        D bool    // 1 byte
    }
    
    fmt.Printf("AlignmentExample 大小: %d bytes\n", unsafe.Sizeof(AlignmentExample{})) // 24 bytes
    
    ae := AlignmentExample{}
    fmt.Printf("A偏移: %d, B偏移: %d, C偏移: %d, D偏移: %d\n",
        unsafe.Offsetof(ae.A), // 0
        unsafe.Offsetof(ae.B), // 8 (对齐到8字节边界)
        unsafe.Offsetof(ae.C), // 16
        unsafe.Offsetof(ae.D)) // 20
}

::: :::

3. 结构体比较

点击查看完整代码实现
点击查看完整代码实现
点击查看完整代码实现
go
type ComparableStruct struct {
    Name  string
    Age   int
    Score float64
}

type NonComparableStruct struct {
    Name   string
    Scores []int  // 切片使结构体不可比较
}

func demonstrateStructComparison() {
    // 可比较的结构体
    s1 := ComparableStruct{Name: "Alice", Age: 30, Score: 95.5}
    s2 := ComparableStruct{Name: "Alice", Age: 30, Score: 95.5}
    s3 := ComparableStruct{Name: "Bob", Age: 30, Score: 95.5}
    
    fmt.Printf("s1 == s2: %t\n", s1 == s2) // true
    fmt.Printf("s1 == s3: %t\n", s1 == s3) // false
    
    // 不可比较的结构体
    ns1 := NonComparableStruct{Name: "Alice", Scores: []int{1, 2, 3}}
    ns2 := NonComparableStruct{Name: "Alice", Scores: []int{1, 2, 3}}
    
    // 这行代码会编译错误:invalid operation: ns1 == ns2
    // fmt.Printf("ns1 == ns2: %t\n", ns1 == ns2)
    
    // 需要使用reflect.DeepEqual进行比较
    fmt.Printf("ns1 深度相等 ns2: %t\n", reflect.DeepEqual(ns1, ns2)) // true
    
    // 可比较字段的组合
    type MixedStruct struct {
        Name   string
        Age    int
        Data   [3]int    // 数组是可比较的
        // Slice  []int    // 如果有这个字段,整个结构体就不可比较
    }
    
    ms1 := MixedStruct{Name: "Test", Age: 1, Data: [3]int{1, 2, 3}}
    ms2 := MixedStruct{Name: "Test", Age: 1, Data: [3]int{1, 2, 3}}
    fmt.Printf("ms1 == ms2: %t\n", ms1 == ms2) // true
}

::: :::

面试题 2:结构体方法和接收器

难度级别:⭐⭐⭐⭐
考察范围:方法定义/接收器类型
技术标签method receiver value receiver pointer receiver

问题分析

理解值接收器和指针接收器的区别,以及它们对方法集的影响,是掌握Go语言面向对象特性的关键。

详细解答

1. 值接收器vs指针接收器

点击查看完整代码实现
点击查看完整代码实现
点击查看完整代码实现
go
type Counter struct {
    count int
}

// 值接收器方法
func (c Counter) GetValue() int {
    return c.count
}

// 值接收器修改方法(不会改变原始值)
func (c Counter) IncrementValue() {
    c.count++  // 只修改副本
}

// 指针接收器修改方法(会改变原始值)
func (c *Counter) IncrementPointer() {
    c.count++  // 修改原始值
}

// 指针接收器读取方法
func (c *Counter) GetValuePointer() int {
    return c.count
}

func demonstrateReceiverTypes() {
    counter := Counter{count: 0}
    
    fmt.Printf("初始值: %d\n", counter.count) // 0
    
    // 值接收器调用
    fmt.Printf("GetValue(): %d\n", counter.GetValue()) // 0
    
    counter.IncrementValue()
    fmt.Printf("调用IncrementValue()后: %d\n", counter.count) // 0 (没有改变)
    
    // 指针接收器调用
    counter.IncrementPointer()
    fmt.Printf("调用IncrementPointer()后: %d\n", counter.count) // 1 (改变了)
    
    fmt.Printf("GetValuePointer(): %d\n", counter.GetValuePointer()) // 1
    
    // Go自动处理指针和值的转换
    counterPtr := &Counter{count: 10}
    
    // 值接收器方法可以通过指针调用
    fmt.Printf("通过指针调用值接收器: %d\n", counterPtr.GetValue()) // 10
    
    // 指针接收器方法可以通过值调用(Go自动获取地址)
    counter2 := Counter{count: 20}
    counter2.IncrementPointer() // Go自动转换为(&counter2).IncrementPointer()
    fmt.Printf("通过值调用指针接收器: %d\n", counter2.count) // 21
}

::: :::

2. 方法集和接口实现

点击查看完整代码实现
点击查看完整代码实现
点击查看完整代码实现
go
type Reader interface {
    Read() string
}

type Writer interface {
    Write(string)
}

type ReadWriter interface {
    Reader
    Writer
}

type Document struct {
    content string
}

// 值接收器方法
func (d Document) Read() string {
    return d.content
}

// 指针接收器方法
func (d *Document) Write(content string) {
    d.content = content
}

func demonstrateMethodSets() {
    doc := Document{content: "initial content"}
    docPtr := &doc
    
    // 值类型的方法集
    var reader1 Reader = doc    // ✅ 值类型可以实现值接收器方法
    var reader2 Reader = docPtr // ✅ 指针类型也可以调用值接收器方法
    
    fmt.Printf("reader1.Read(): %s\n", reader1.Read())
    fmt.Printf("reader2.Read(): %s\n", reader2.Read())
    
    // 指针类型的方法集
    // var writer1 Writer = doc    // ❌ 值类型不能实现指针接收器方法
    var writer2 Writer = docPtr   // ✅ 指针类型可以实现指针接收器方法
    
    writer2.Write("new content")
    fmt.Printf("写入后内容: %s\n", doc.content)
    
    // 组合接口只能由指针类型实现
    // var readWriter1 ReadWriter = doc    // ❌ 值类型无法同时实现
    var readWriter2 ReadWriter = docPtr   // ✅ 指针类型可以实现
    
    readWriter2.Write("final content")
    fmt.Printf("最终内容: %s\n", readWriter2.Read())
    
    // 方法集规则总结
    printMethodSet("Document", doc)
    printMethodSet("*Document", docPtr)
}

func printMethodSet(typeName string, value interface{}) {
    t := reflect.TypeOf(value)
    fmt.Printf("\n%s 的方法集:\n", typeName)
    for i := 0; i < t.NumMethod(); i++ {
        method := t.Method(i)
        fmt.Printf("  %s: %v\n", method.Name, method.Type)
    }
}

::: :::

3. 方法值和方法表达式

点击查看完整代码实现
点击查看完整代码实现
点击查看完整代码实现
go
func demonstrateMethodValuesAndExpressions() {
    counter := &Counter{count: 5}
    
    // 方法值 (Method Values)
    getValue := counter.GetValue
    increment := counter.IncrementPointer
    
    fmt.Printf("方法值调用: %d\n", getValue()) // 5
    increment()
    fmt.Printf("递增后: %d\n", getValue()) // 6
    
    // 方法表达式 (Method Expressions)
    getValueExpr := (*Counter).GetValue
    incrementExpr := (*Counter).IncrementPointer
    
    fmt.Printf("方法表达式调用: %d\n", getValueExpr(counter)) // 6
    incrementExpr(counter)
    fmt.Printf("表达式递增后: %d\n", getValueExpr(counter)) // 7
    
    // 值类型的方法表达式
    valueGetExpr := Counter.GetValue
    incrementValueExpr := Counter.IncrementValue
    
    counterValue := Counter{count: 10}
    fmt.Printf("值类型方法表达式: %d\n", valueGetExpr(counterValue)) // 10
    incrementValueExpr(counterValue)
    fmt.Printf("值类型递增(无效果): %d\n", counterValue.count) // 10
}

::: :::

面试题 3:结构体嵌套和组合

难度级别:⭐⭐⭐⭐
考察范围:嵌套结构/字段提升
技术标签embedding composition field promotion anonymous fields

问题分析

结构体嵌套是Go语言实现类似继承功能的重要机制,理解字段提升和方法提升的规则至关重要。

详细解答

1. 结构体嵌套基础

点击查看完整代码实现
点击查看完整代码实现
点击查看完整代码实现
go
// 基础结构体
type Address struct {
    Street   string
    City     string
    Country  string
    ZipCode  string
}

func (a Address) String() string {
    return fmt.Sprintf("%s, %s, %s %s", a.Street, a.City, a.Country, a.ZipCode)
}

func (a Address) IsInCountry(country string) bool {
    return a.Country == country
}

// 联系信息
type Contact struct {
    Phone string
    Email string
}

func (c Contact) String() string {
    return fmt.Sprintf("Phone: %s, Email: %s", c.Phone, c.Email)
}

// 嵌套结构体
type Person struct {
    Name    string
    Age     int
    Address // 匿名字段,字段提升
    Contact // 匿名字段
}

// Person的方法
func (p Person) String() string {
    return fmt.Sprintf("Name: %s, Age: %d\nAddress: %s\nContact: %s",
        p.Name, p.Age, p.Address.String(), p.Contact.String())
}

func demonstrateStructEmbedding() {
    person := Person{
        Name: "Alice",
        Age:  30,
        Address: Address{
            Street:  "123 Main St",
            City:    "New York",
            Country: "USA",
            ZipCode: "10001",
        },
        Contact: Contact{
            Phone: "555-1234",
            Email: "alice@example.com",
        },
    }
    
    // 字段提升:可以直接访问嵌套字段
    fmt.Printf("直接访问Street: %s\n", person.Street)
    fmt.Printf("直接访问Phone: %s\n", person.Phone)
    
    // 完整路径访问
    fmt.Printf("完整路径Street: %s\n", person.Address.Street)
    fmt.Printf("完整路径Phone: %s\n", person.Contact.Phone)
    
    // 方法提升:可以直接调用嵌套结构体的方法
    fmt.Printf("IsInCountry(USA): %t\n", person.IsInCountry("USA"))
    
    // 显式调用嵌套结构体方法
    fmt.Printf("Address.String(): %s\n", person.Address.String())
    fmt.Printf("Contact.String(): %s\n", person.Contact.String())
    
    fmt.Printf("Person.String():\n%s\n", person.String())
}

::: :::

2. 复杂嵌套和命名冲突

点击查看完整代码实现
点击查看完整代码实现
点击查看完整代码实现
go
type Base struct {
    ID   int
    Name string
}

func (b Base) GetInfo() string {
    return fmt.Sprintf("Base: ID=%d, Name=%s", b.ID, b.Name)
}

type Extended struct {
    ID   int    // 与Base.ID冲突
    Type string
    Base        // 嵌套Base
}

func (e Extended) GetInfo() string {
    return fmt.Sprintf("Extended: ID=%d, Type=%s", e.ID, e.Type)
}

func demonstrateFieldConflicts() {
    ext := Extended{
        ID:   100,  // Extended的ID
        Type: "extended",
        Base: Base{
            ID:   200,  // Base的ID
            Name: "base",
        },
    }
    
    // 访问字段
    fmt.Printf("ext.ID: %d\n", ext.ID)           // 100 (Extended的ID)
    fmt.Printf("ext.Base.ID: %d\n", ext.Base.ID) // 200 (Base的ID)
    fmt.Printf("ext.Name: %s\n", ext.Name)       // "base" (提升的字段)
    fmt.Printf("ext.Type: %s\n", ext.Type)       // "extended"
    
    // 方法调用
    fmt.Printf("ext.GetInfo(): %s\n", ext.GetInfo())      // Extended的方法
    fmt.Printf("ext.Base.GetInfo(): %s\n", ext.Base.GetInfo()) // Base的方法
}

::: :::

3. 多重嵌套和接口实现

点击查看完整代码实现
点击查看完整代码实现
点击查看完整代码实现
go
// 定义接口
type Stringer interface {
    String() string
}

type Validator interface {
    Validate() error
}

type Serializer interface {
    Serialize() ([]byte, error)
}

// 基础功能
type BaseEntity struct {
    ID        int
    CreatedAt time.Time
}

func (be BaseEntity) String() string {
    return fmt.Sprintf("Entity{ID: %d, Created: %v}", be.ID, be.CreatedAt.Format("2006-01-02"))
}

func (be BaseEntity) Validate() error {
    if be.ID <= 0 {
        return fmt.Errorf("invalid ID: %d", be.ID)
    }
    return nil
}

// 可序列化的实体
type SerializableEntity struct {
    BaseEntity
    Version int
}

func (se SerializableEntity) Serialize() ([]byte, error) {
    return json.Marshal(map[string]interface{}{
        "id":         se.ID,
        "created_at": se.CreatedAt,
        "version":    se.Version,
    })
}

// 用户实体
type User struct {
    SerializableEntity
    Name  string
    Email string
}

func (u User) String() string {
    return fmt.Sprintf("User{%s, Name: %s, Email: %s}", 
        u.BaseEntity.String(), u.Name, u.Email)
}

func (u User) Validate() error {
    if err := u.BaseEntity.Validate(); err != nil {
        return err
    }
    if u.Name == "" {
        return fmt.Errorf("name is required")
    }
    if u.Email == "" {
        return fmt.Errorf("email is required")
    }
    return nil
}

func demonstrateMultipleEmbedding() {
    user := User{
        SerializableEntity: SerializableEntity{
            BaseEntity: BaseEntity{
                ID:        1,
                CreatedAt: time.Now(),
            },
            Version: 1,
        },
        Name:  "Alice",
        Email: "alice@example.com",
    }
    
    // 实现的接口
    var stringer Stringer = user
    var validator Validator = user
    var serializer Serializer = user
    
    fmt.Printf("String(): %s\n", stringer.String())
    
    if err := validator.Validate(); err != nil {
        fmt.Printf("验证失败: %v\n", err)
    } else {
        fmt.Println("验证通过")
    }
    
    if data, err := serializer.Serialize(); err != nil {
        fmt.Printf("序列化失败: %v\n", err)
    } else {
        fmt.Printf("序列化结果: %s\n", string(data))
    }
    
    // 字段提升的完整路径
    fmt.Printf("user.ID: %d\n", user.ID)                    // 提升字段
    fmt.Printf("user.BaseEntity.ID: %d\n", user.BaseEntity.ID) // 完整路径
    fmt.Printf("user.SerializableEntity.BaseEntity.ID: %d\n", 
        user.SerializableEntity.BaseEntity.ID)               // 最完整路径
}

::: :::

面试题 4:结构体标签和反射

难度级别:⭐⭐⭐⭐⭐
考察范围:结构体标签/反射机制
技术标签struct tags reflection json xml validation

问题分析

结构体标签是Go语言的重要特性,广泛用于序列化、验证、ORM映射等场景。理解标签的使用和反射访问是高级开发的必备技能。

详细解答

1. 结构体标签的基本使用

点击查看完整代码实现
点击查看完整代码实现
点击查看完整代码实现
go
import (
    "encoding/json"
    "encoding/xml"
    "reflect"
    "strings"
)

type Product struct {
    ID          int     `json:"id" xml:"id,attr" db:"product_id" validate:"required"`
    Name        string  `json:"name" xml:"name" db:"product_name" validate:"required,min=1,max=100"`
    Price       float64 `json:"price" xml:"price" db:"price" validate:"required,min=0"`
    Description string  `json:"description,omitempty" xml:"description,omitempty" db:"description"`
    Category    string  `json:"category" xml:"category" db:"category_id" validate:"required"`
    InStock     bool    `json:"in_stock" xml:"in_stock" db:"in_stock"`
    Tags        []string `json:"tags,omitempty" xml:"tags>tag" db:"-"` // db:"-" 表示数据库忽略
}

func demonstrateStructTags() {
    product := Product{
        ID:          1,
        Name:        "Laptop",
        Price:       999.99,
        Description: "High-performance laptop",
        Category:    "Electronics",
        InStock:     true,
        Tags:        []string{"computer", "portable", "work"},
    }
    
    // JSON序列化
    jsonData, _ := json.MarshalIndent(product, "", "  ")
    fmt.Printf("JSON序列化:\n%s\n", jsonData)
    
    // XML序列化
    xmlData, _ := xml.MarshalIndent(product, "", "  ")
    fmt.Printf("XML序列化:\n%s\n", xmlData)
    
    // 反序列化测试
    jsonStr := `{"id":2,"name":"Phone","price":599.99,"category":"Mobile","in_stock":false}`
    var newProduct Product
    json.Unmarshal([]byte(jsonStr), &newProduct)
    fmt.Printf("JSON反序列化: %+v\n", newProduct)
}

::: :::

2. 自定义标签解析

点击查看完整代码实现
点击查看完整代码实现
点击查看完整代码实现
go
// 验证标签解析器
type ValidationRule struct {
    Field    string
    Required bool
    Min      int
    Max      int
    Options  []string
}

func parseValidationTag(tag string) ValidationRule {
    rule := ValidationRule{}
    
    parts := strings.Split(tag, ",")
    for _, part := range parts {
        part = strings.TrimSpace(part)
        
        if part == "required" {
            rule.Required = true
        } else if strings.HasPrefix(part, "min=") {
            fmt.Sscanf(part, "min=%d", &rule.Min)
        } else if strings.HasPrefix(part, "max=") {
            fmt.Sscanf(part, "max=%d", &rule.Max)
        }
    }
    
    return rule
}

// 通用验证函数
func validateStruct(v interface{}) []error {
    var errors []error
    
    rv := reflect.ValueOf(v)
    rt := reflect.TypeOf(v)
    
    if rv.Kind() == reflect.Ptr {
        rv = rv.Elem()
        rt = rt.Elem()
    }
    
    for i := 0; i < rv.NumField(); i++ {
        field := rv.Field(i)
        fieldType := rt.Field(i)
        
        // 获取validate标签
        validateTag := fieldType.Tag.Get("validate")
        if validateTag == "" {
            continue
        }
        
        rule := parseValidationTag(validateTag)
        rule.Field = fieldType.Name
        
        // 检查required
        if rule.Required && isZeroValue(field) {
            errors = append(errors, fmt.Errorf("field %s is required", rule.Field))
        }
        
        // 检查字符串长度
        if field.Kind() == reflect.String {
            str := field.String()
            if rule.Min > 0 && len(str) < rule.Min {
                errors = append(errors, fmt.Errorf("field %s is too short (min: %d)", rule.Field, rule.Min))
            }
            if rule.Max > 0 && len(str) > rule.Max {
                errors = append(errors, fmt.Errorf("field %s is too long (max: %d)", rule.Field, rule.Max))
            }
        }
        
        // 检查数值范围
        if field.Kind() == reflect.Float64 || field.Kind() == reflect.Float32 {
            val := field.Float()
            if rule.Min > 0 && val < float64(rule.Min) {
                errors = append(errors, fmt.Errorf("field %s is too small (min: %d)", rule.Field, rule.Min))
            }
        }
    }
    
    return errors
}

func isZeroValue(v reflect.Value) bool {
    switch v.Kind() {
    case reflect.String:
        return v.String() == ""
    case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
        return v.Int() == 0
    case reflect.Float32, reflect.Float64:
        return v.Float() == 0
    case reflect.Bool:
        return !v.Bool()
    case reflect.Slice, reflect.Map:
        return v.IsNil() || v.Len() == 0
    case reflect.Ptr, reflect.Interface:
        return v.IsNil()
    default:
        return false
    }
}

func demonstrateCustomValidation() {
    // 有效的产品
    validProduct := Product{
        ID:       1,
        Name:     "Valid Product",
        Price:    99.99,
        Category: "Electronics",
        InStock:  true,
    }
    
    // 无效的产品
    invalidProduct := Product{
        ID:    0,  // 应该required
        Name:  "", // 应该required且min=1
        Price: -10.0, // 应该min=0
        // Category缺失,应该required
    }
    
    fmt.Println("验证有效产品:")
    if errors := validateStruct(validProduct); len(errors) > 0 {
        for _, err := range errors {
            fmt.Printf("  - %v\n", err)
        }
    } else {
        fmt.Println("  验证通过")
    }
    
    fmt.Println("\n验证无效产品:")
    if errors := validateStruct(invalidProduct); len(errors) > 0 {
        for _, err := range errors {
            fmt.Printf("  - %v\n", err)
        }
    } else {
        fmt.Println("  验证通过")
    }
}

::: :::

3. 反射操作结构体

点击查看完整代码实现
点击查看完整代码实现
点击查看完整代码实现
go
func demonstrateStructReflection() {
    product := Product{
        ID:          1,
        Name:        "Reflection Test",
        Price:       199.99,
        Description: "Testing reflection",
        Category:    "Test",
        InStock:     true,
    }
    
    rv := reflect.ValueOf(&product).Elem()
    rt := reflect.TypeOf(product)
    
    fmt.Println("结构体字段信息:")
    for i := 0; i < rv.NumField(); i++ {
        field := rv.Field(i)
        fieldType := rt.Field(i)
        
        fmt.Printf("字段 %s:\n", fieldType.Name)
        fmt.Printf("  类型: %s\n", field.Type())
        fmt.Printf("  值: %v\n", field.Interface())
        fmt.Printf("  可设置: %t\n", field.CanSet())
        
        // 显示标签
        if jsonTag := fieldType.Tag.Get("json"); jsonTag != "" {
            fmt.Printf("  JSON标签: %s\n", jsonTag)
        }
        if validateTag := fieldType.Tag.Get("validate"); validateTag != "" {
            fmt.Printf("  验证标签: %s\n", validateTag)
        }
        fmt.Println()
    }
    
    // 通过反射修改字段值
    nameField := rv.FieldByName("Name")
    if nameField.IsValid() && nameField.CanSet() {
        nameField.SetString("Modified by Reflection")
        fmt.Printf("修改后的Name: %s\n", product.Name)
    }
    
    // 通过反射调用方法
    // 如果Product有方法,可以这样调用
    methodValue := reflect.ValueOf(product).MethodByName("String")
    if methodValue.IsValid() {
        result := methodValue.Call(nil)
        if len(result) > 0 {
            fmt.Printf("方法调用结果: %v\n", result[0].Interface())
        }
    }
}

// 通用结构体复制函数
func copyStruct(src, dst interface{}) error {
    srcVal := reflect.ValueOf(src)
    dstVal := reflect.ValueOf(dst)
    
    if srcVal.Kind() == reflect.Ptr {
        srcVal = srcVal.Elem()
    }
    if dstVal.Kind() != reflect.Ptr {
        return fmt.Errorf("destination must be a pointer")
    }
    dstVal = dstVal.Elem()
    
    srcType := srcVal.Type()
    dstType := dstVal.Type()
    
    for i := 0; i < srcVal.NumField(); i++ {
        srcField := srcVal.Field(i)
        srcFieldType := srcType.Field(i)
        
        dstField := dstVal.FieldByName(srcFieldType.Name)
        if !dstField.IsValid() || !dstField.CanSet() {
            continue
        }
        
        if srcField.Type() == dstField.Type() {
            dstField.Set(srcField)
        }
    }
    
    return nil
}

func demonstrateStructCopy() {
    src := Product{
        ID:       1,
        Name:     "Source Product",
        Price:    99.99,
        Category: "Electronics",
        InStock:  true,
    }
    
    var dst Product
    
    err := copyStruct(src, &dst)
    if err != nil {
        fmt.Printf("复制失败: %v\n", err)
        return
    }
    
    fmt.Printf("源结构体: %+v\n", src)
    fmt.Printf("目标结构体: %+v\n", dst)
}

::: :::

🎯 核心知识点总结

结构体基础要点

  1. 零值初始化: 结构体的零值是所有字段的零值
  2. 初始化方式: 零值、字面量、指定字段名、new函数等多种方式
  3. 内存布局: 字段顺序影响内存对齐和结构体大小
  4. 可比较性: 只有所有字段都可比较的结构体才可比较

方法和接收器要点

  1. 值接收器: 操作结构体的副本,不改变原始值
  2. 指针接收器: 操作结构体的原始值,可以修改
  3. 方法集: 值类型和指针类型的方法集不同
  4. 自动转换: Go会在值和指针之间自动转换以调用方法

结构体嵌套要点

  1. 字段提升: 匿名嵌套字段的字段和方法被提升到外层
  2. 命名冲突: 外层字段优先,可通过完整路径访问内层字段
  3. 方法提升: 嵌套结构体的方法也会被提升
  4. 接口实现: 通过嵌套可以组合实现复杂接口

结构体标签要点

  1. 标签语法: 使用反引号包围,键值对格式
  2. 标准标签: json、xml、db等标准库和第三方库使用的标签
  3. 自定义解析: 可以通过反射解析自定义标签
  4. 验证应用: 标签广泛用于数据验证和对象关系映射

🔍 面试准备建议

  1. 掌握基础语法: 熟练掌握结构体定义和初始化的各种方式
  2. 理解内存模型: 了解结构体的内存布局和对齐规则
  3. 区分接收器类型: 清楚值接收器和指针接收器的使用场景
  4. 活用嵌套组合: 掌握结构体嵌套实现代码复用的技巧
  5. 熟悉标签应用: 了解常见标签的使用和自定义标签解析

正在精进