MST

星途 面试题库

面试题:Go反射在动态类型序列化及自定义标签处理中的应用

假设存在一个接口类型type Data interface{},它可能传入不同类型的结构体,且结构体可能包含自定义标签(非json标准标签),如type Person struct { Name string `serialize:"person_name"` Gender string `serialize:"person_gender"` } 请使用反射实现一个通用的序列化函数,能根据自定义标签将各种不同类型的结构体序列化为特定格式(格式自定义,但要体现标签的使用),同时要处理好循环引用问题。
29.0万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
package main

import (
    "fmt"
    "reflect"
)

// 定义序列化结果的格式
type SerializedResult struct {
    Fields map[string]interface{}
}

// 用于记录已经处理过的对象,避免循环引用
var visited = make(map[interface{}]bool)

func serialize(data interface{}) (SerializedResult, error) {
    var result SerializedResult
    result.Fields = make(map[string]interface{})

    value := reflect.ValueOf(data)
    if value.Kind() == reflect.Ptr {
        value = value.Elem()
    }

    if value.Kind() != reflect.Struct {
        return result, fmt.Errorf("unsupported type: %v", value.Kind())
    }

    if _, ok := visited[data]; ok {
        return result, fmt.Errorf("circular reference detected")
    }
    visited[data] = true
    defer delete(visited, data)

    typeOf := value.Type()
    for i := 0; i < value.NumField(); i++ {
        field := value.Field(i)
        tag := typeOf.Field(i).Tag.Get("serialize")
        if tag != "" {
            if field.Kind() == reflect.Struct {
                subResult, err := serialize(field.Interface())
                if err != nil {
                    return result, err
                }
                result.Fields[tag] = subResult.Fields
            } else {
                result.Fields[tag] = field.Interface()
            }
        }
    }

    return result, nil
}

你可以使用以下方式调用这个函数:

func main() {
    type Person struct {
        Name    string `serialize:"person_name"`
        Gender  string `serialize:"person_gender"`
        Friends []Person `serialize:"friends"`
    }

    p1 := Person{
        Name:    "Alice",
        Gender:  "Female",
        Friends: []Person{},
    }
    p2 := Person{
        Name:    "Bob",
        Gender:  "Male",
        Friends: []Person{p1},
    }
    p1.Friends = append(p1.Friends, p2)

    result, err := serialize(p1)
    if err != nil {
        fmt.Println("Serialization error:", err)
        return
    }
    fmt.Printf("Serialized result: %+v\n", result)
}

上述代码实现了以下功能:

  1. serialize 函数接受一个 interface{} 类型的参数,利用反射获取结构体的字段及其自定义标签。
  2. 将结构体序列化为包含自定义标签和对应值的 SerializedResult 格式。
  3. 处理了结构体中的循环引用问题,通过 visited map 来记录已经处理过的对象,如果检测到循环引用则返回错误。

main 函数中,定义了一个包含嵌套和循环引用的 Person 结构体,并调用 serialize 函数进行序列化。