MST

星途 面试题库

面试题:Go反射第二定律在复杂数据结构处理中的体现

在Go语言中,反射第二定律是‘反射可以从反射对象获取接口值’。假设有一个嵌套的结构体,结构体中包含数组、切片、map等复杂数据结构,要求通过反射获取其所有字段值并进行修改,然后再通过反射将修改后的值还原回去。请阐述实现思路并给出核心代码。
45.4万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

实现思路

  1. 使用 reflect.ValueOf 获取结构体的 reflect.Value,并通过 Elem 方法获取可设置的 reflect.Value(如果是指针类型)。
  2. 遍历结构体的字段,对于每个字段,根据其类型进行不同处理:
    • 如果是数组或切片,递归处理每个元素。
    • 如果是 map,遍历 map 的键值对并递归处理值。
    • 如果是结构体,递归处理结构体的所有字段。
  3. 保存原始值,修改字段值。
  4. 处理完所有字段后,再通过反射将修改前保存的值还原回去。

核心代码

package main

import (
    "fmt"
    "reflect"
)

// 定义嵌套结构体
type Inner struct {
    Name string
}

type Outer struct {
    ID    int
    Inner Inner
    Data  []int
    Map   map[string]int
}

func modifyAndRestore(obj interface{}) {
    valueOf := reflect.ValueOf(obj)
    if valueOf.Kind() == reflect.Ptr {
        valueOf = valueOf.Elem()
    }
    if valueOf.Kind() != reflect.Struct {
        panic("obj must be a struct or a pointer to a struct")
    }

    // 保存原始值
    originalValues := make([]reflect.Value, valueOf.NumField())
    for i := 0; i < valueOf.NumField(); i++ {
        originalValues[i] = valueOf.Field(i).Clone()
    }

    // 修改值
    for i := 0; i < valueOf.NumField(); i++ {
        modifyField(valueOf.Field(i))
    }

    // 还原值
    for i := 0; i < valueOf.NumField(); i++ {
        valueOf.Field(i).Set(originalValues[i])
    }
}

func modifyField(field reflect.Value) {
    switch field.Kind() {
    case reflect.Struct:
        for i := 0; i < field.NumField(); i++ {
            modifyField(field.Field(i))
        }
    case reflect.Array, reflect.Slice:
        for i := 0; i < field.Len(); i++ {
            modifyField(field.Index(i))
        }
    case reflect.Map:
        for _, key := range field.MapKeys() {
            modifyField(field.MapIndex(key))
        }
    default:
        // 这里可以进行具体的修改操作,比如将所有字符串字段改为 "modified"
        if field.Kind() == reflect.String {
            field.SetString("modified")
        }
    }
}

func main() {
    o := Outer{
        ID: 1,
        Inner: Inner{
            Name: "original",
        },
        Data: []int{1, 2, 3},
        Map:  map[string]int{"key": 1},
    }

    modifyAndRestore(&o)
    fmt.Printf("Restored object: %+v\n", o)
}