You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Go中json.Unmarshal将静态类型any的结构体解码为map而非填充结构体?

为什么传入静态类型为any的结构体变量给json.Unmarshal会被解析为map[string]any?

问题核心

当把静态类型为any、实际存储Foo结构体实例的变量指针传给json.Unmarshal时,Unmarshal不会复用原本的结构体实例,反而会将其替换为map[string]any类型对象,这是Go标准库json包的解析规则导致的。

原因解析

Go的any本质就是interface{},当你传入&dest2(类型为*any)时,Unmarshal会根据指针指向的静态类型(即any)来处理:

  • 对于指向interface{}的指针,json包默认会把JSON对象解析为map[string]any,并将这个map赋值给该interface{}变量,直接覆盖原本存储的结构体实例。
  • 而第一个案例中&dest的类型是*Foo,Unmarshal明确知道要解析到Foo结构体,因此会匹配JSON字段到结构体对应字段完成填充。

解决方案

方案1:类型断言后传入指针

如果提前知道any变量存储的具体类型,可以先做类型断言,再将断言后的实例指针传入:

dest2 := getFooAny()
// 断言为Foo类型,创建可修改的实例指针
foo, ok := dest2.(Foo)
if !ok {
    // 处理类型不匹配的异常情况
}
err = decodeAny(&foo)
dest2 = foo // 将解析后的结果赋值回dest2

方案2:使用reflect动态创建实例

如果无法提前确定类型,可以利用reflect包获取原实例的类型,创建新的实例指针传入解析,再将结果赋值回原变量:

dest2 := getFooAny()
// 获取原实例的类型
t := reflect.TypeOf(dest2)
// 创建该类型的指针实例
newDest := reflect.New(t).Interface()
// 解析JSON到新实例
err = decodeAny(newDest)
if err != nil {
    // 处理解析错误
}
// 将新实例的值提取出来赋值给dest2
dest2 = reflect.ValueOf(newDest).Elem().Interface()

原示例代码

package main

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

type Foo struct {
    Name   string `json:"name"`
    Number int    `json:"number"`
}

const jsonStr = `{"name": "testing", "number": 22}`

func decodeAny(dest any) error {
    return json.Unmarshal([]byte(jsonStr), dest)
}

func getFooAny() any {
    return Foo{}
}

func main() {
    dest := Foo{}
    err := decodeAny(&dest)
    fmt.Printf("err: %v\n", err) // err is nil
    fmt.Printf("dest %v of type %T\n", dest, dest)  // dest is a Foo

    dest2 := getFooAny()
    fmt.Printf("Initial type of dest2: %T\n", dest2) // dest2 is a Foo
    fmt.Printf("Checking with reflect: %v\n", reflect.TypeOf(dest2)) // TypeOf shows dest2 is Foo
    err = decodeAny(&dest2)
    fmt.Printf("err: %v\n", err) // Err is nil
    fmt.Printf("dest2 %v of type %T\n", dest2, dest2) // dest2 is now a map[string]any
}

内容的提问来源于stack exchange,提问作者Oliver Dain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 21:37:35