面试题答案
一键面试实现通用结构体到JSON格式字符串转换函数
- 初始化反射值:通过
reflect.ValueOf
获取结构体实例的反射值对象,使用reflect.TypeOf
获取结构体类型对象。 - 遍历结构体字段:通过
Type.NumField
获取结构体字段数量,使用Type.Field(i)
获取每个字段的StructField
信息,Value.Field(i)
获取对应字段的值。 - 处理不同类型字段:
- 基本类型:直接获取值并转换为JSON格式字符串。
- 指针类型:先判断是否为
nil
,非nil
则解引用获取实际值。 - 切片、数组:递归处理每个元素。
- 嵌套结构体:递归调用转换函数。
- 构建JSON字符串:根据JSON格式要求,拼接字段名、冒号、字段值,并处理好逗号分隔及大括号包围。
反射工作原理
- 获取结构体字段信息:
reflect.Type
的Field
方法能获取结构体中每个字段的详细信息,如名字、类型、标签等。标签信息可用于自定义JSON序列化时的字段名等。reflect.Value
的Field
方法获取对应字段的实际值。
- 处理不同类型字段:
- 基本类型:
reflect.Value
有对应方法获取基本类型的值,如Int
获取int
值,Float
获取float64
值等,获取值后按JSON格式要求转换。 - 指针类型:
reflect.Value
的IsNil
方法判断指针是否为空,Elem
方法获取指针指向的值。 - 切片、数组:
reflect.Value
的Len
获取长度,Index
获取每个元素值,递归处理每个元素。 - 嵌套结构体:递归调用转换函数,对嵌套结构体进行同样的反射处理。
- 基本类型:
以下是示例代码:
package main
import (
"encoding/json"
"fmt"
"reflect"
)
func structToJSON(obj interface{}) (string, error) {
val := reflect.ValueOf(obj)
if val.Kind() == reflect.Ptr {
val = val.Elem()
}
if val.Kind() != reflect.Struct {
return "", fmt.Errorf("input is not a struct")
}
typeOf := val.Type()
jsonStr := "{"
for i := 0; i < val.NumField(); i++ {
field := typeOf.Field(i)
fieldVal := val.Field(i)
jsonTag := field.Tag.Get("json")
if jsonTag == "" {
jsonTag = field.Name
}
jsonStr += fmt.Sprintf("\"%s\":", jsonTag)
switch fieldVal.Kind() {
case reflect.String:
jsonStr += fmt.Sprintf("\"%s\"", fieldVal.String())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
jsonStr += fmt.Sprintf("%d", fieldVal.Int())
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
jsonStr += fmt.Sprintf("%d", fieldVal.Uint())
case reflect.Float32, reflect.Float64:
jsonStr += fmt.Sprintf("%f", fieldVal.Float())
case reflect.Bool:
jsonStr += fmt.Sprintf("%t", fieldVal.Bool())
case reflect.Struct:
subJSON, err := structToJSON(fieldVal.Interface())
if err != nil {
return "", err
}
jsonStr += subJSON
case reflect.Ptr:
if fieldVal.IsNil() {
jsonStr += "null"
} else {
subJSON, err := structToJSON(fieldVal.Elem().Interface())
if err != nil {
return "", err
}
jsonStr += subJSON
}
case reflect.Slice, reflect.Array:
jsonStr += "["
for j := 0; j < fieldVal.Len(); j++ {
elem := fieldVal.Index(j)
subJSON, err := structToJSON(elem.Interface())
if err != nil {
return "", err
}
jsonStr += subJSON
if j < fieldVal.Len()-1 {
jsonStr += ","
}
}
jsonStr += "]"
default:
return "", fmt.Errorf("unsupported type %v", fieldVal.Kind())
}
if i < val.NumField()-1 {
jsonStr += ","
}
}
jsonStr += "}"
return jsonStr, nil
}
使用示例:
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
func main() {
p := Person{Name: "John", Age: 30}
jsonStr, err := structToJSON(p)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(jsonStr)
var p2 Person
err = json.Unmarshal([]byte(jsonStr), &p2)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(p2)
}