MST

星途 面试题库

面试题:Go反射实现一个通用的对象序列化框架

要求使用Go反射实现一个简单的通用对象序列化框架,能够将任意结构体及其嵌套结构体序列化为类似JSON格式的字符串(不必严格遵循JSON标准格式)。考虑如何处理结构体中的不同类型字段,如基本类型、切片、嵌套结构体等。阐述整体设计思路,并给出关键实现代码。
29.8万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 遍历结构体字段:使用Go的反射机制获取结构体的类型和值。通过reflect.TypeOfreflect.ValueOf函数来操作。
  2. 处理不同类型字段
    • 基本类型:直接获取其值并转换为字符串。
    • 切片:递归处理切片中的每个元素。
    • 嵌套结构体:同样递归进行序列化。
  3. 构建序列化字符串:按照类似JSON的格式,使用strings.Builder来高效构建字符串。

关键实现代码

package main

import (
    "fmt"
    "reflect"
    "strings"
)

func serialize(obj interface{}) string {
    var sb strings.Builder
    sb.WriteByte('{')
    value := reflect.ValueOf(obj)
    typ := reflect.TypeOf(obj)

    for i := 0; i < value.NumField(); i++ {
        fieldValue := value.Field(i)
        fieldType := typ.Field(i)

        sb.WriteString(fmt.Sprintf("\"%s\":", fieldType.Name))
        serializeField(fieldValue, &sb)

        if i < value.NumField()-1 {
            sb.WriteByte(',')
        }
    }
    sb.WriteByte('}')
    return sb.String()
}

func serializeField(field reflect.Value, sb *strings.Builder) {
    switch field.Kind() {
    case reflect.Struct:
        sb.WriteByte('{')
        for j := 0; j < field.NumField(); j++ {
            subFieldValue := field.Field(j)
            subFieldType := field.Type().Field(j)

            sb.WriteString(fmt.Sprintf("\"%s\":", subFieldType.Name))
            serializeField(subFieldValue, sb)

            if j < field.NumField()-1 {
                sb.WriteByte(',')
            }
        }
        sb.WriteByte('}')
    case reflect.Slice:
        sb.WriteByte('[')
        for k := 0; k < field.Len(); k++ {
            serializeField(field.Index(k), sb)
            if k < field.Len()-1 {
                sb.WriteByte(',')
            }
        }
        sb.WriteByte(']')
    default:
        sb.WriteString(fmt.Sprintf("%v", field.Interface()))
    }
}

测试代码

func main() {
    type Inner struct {
        Name string
    }

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

    outer := Outer{
        ID: 1,
        Data: Inner{
            Name: "example",
        },
        Tags: []string{"tag1", "tag2"},
    }

    result := serialize(outer)
    fmt.Println(result)
}