Go 中的通用解组

Generic unmarshalling in Go

我试图弄清楚是否有一种方法可以仅使用字符串和预期类型将 JSON 字符串解组为特定结构。这是我到目前为止的想法。

代码

package main

import (
    "encoding/json"
    "fmt"
    "reflect"
)

type Person struct {
    Name string `json:"name"`
}

func genericUnmarshal(jsonString string, t reflect.Type) interface{} {
    p := reflect.New(t)
    result := p.Interface()
    json.Unmarshal([]byte(jsonString), &result)
    return result
}

func main() {
    jsonData := "{\"name\":\"John\"}"
    unmarshalledPerson := genericUnmarshal(jsonData, reflect.TypeOf(Person{}))

    person := Person{Name: "John"}
    fmt.Printf("struct value: %+v type: %+v\n", person, reflect.TypeOf(person))
    fmt.Printf("unmarshalled value: %+v type: %+v\n", unmarshalledPerson, reflect.TypeOf(unmarshalledPerson))
    fmt.Printf("are variables equal: %v\n", reflect.DeepEqual(unmarshalledPerson, person))
}

Returns

struct value: {Name:John} type: main.Person
unmarshalled value: &{Name:John} type: *main.Person
are variables equal: false

方法genericUnmarshalreturns指向类型的指针。

我的问题:有没有办法将未编组的值更改为结构(即 Person)而不是指针,以便 reflect.DeepEqual(unmarshalledPerson, person) returns true

您可以比较 person 指针,因为 reflect.DeepEqual() 如果指针值(深度)相等则也接受:

Pointer values are deeply equal if they are equal using Go's == operator or if they point to deeply equal values.

所以简单地做:

fmt.Printf("are variables equal: %v\n",
    reflect.DeepEqual(unmarshalledPerson, &person))

或者取消引用包裹在 unmarshalledPerson 中的 *Person 指针,这样你就得到一个 Person 结构:

fmt.Printf("are variables equal: %v\n",
    reflect.DeepEqual(*unmarshalledPerson.(*Person), person))

两者都打印 true(在 Go Playground 上尝试):

are variables equal: true
are variables equal: true

另请注意,对于您的“简单”结构,您可以使用简单的 == 比较:

*unmarshalledPerson.(*Person) == person

如果您添加其他字段(例如指针、结构、映射等),情况就不会如此