Golang中如何声明并解析包含不同结构体值的map
Golang中如何声明并解析包含不同结构体值的map
package main
import (
"fmt"
"encoding/json"
"log"
)
type X struct {
A int `json:"a,omitempty"`
C int `json:"c,omitempty"`
}
type Y struct {
B int
}
func main() {
type M interface {
}
m := map[string]M{ "k1": X{A:33}, "k2": Y{B:2} }
data := `{"c": 22}`
cc := m["k1"]
fmt.Printf("%#v", cc)
fmt.Println("-------------- ")
err := json.Unmarshal([]byte(data), &cc)
fmt.Printf("%#v", cc)
log.Println(m)
fmt.Println(err)
//fmt.Println("Hello, playground")
}
为什么我无法解组它? 我的输出
main.X{A:33, C:0}--------------
map[string]interface {}{"c":22}2009/11/10 23:00:00 map[k1:{33 0} k2:{2}]
<nil>
更多关于Golang中如何声明并解析包含不同结构体值的map的实战教程也可以访问 https://www.itying.com/category-94-b0.html
是的,这就是唯一的问题……cc 怎么会变成 map[string]interface {}{"c":22}
更多关于Golang中如何声明并解析包含不同结构体值的map的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
你好,@Mukul_Dilwaria,你的代码确实在解组 cc;你的 Printf 显示 cc 中的新值从解组后的 JSON {"c": 22} 变成了 map[string]interface{}。你能说明一下你原本期望的结果吗?
Mukul_Dilwaria:
type M interface { } m := map[string]M{ "k1": X{A:33}, "k2": Y{B:2} }
m的类型是map[string]M,我将其称为与map[string]interface{}类型"等效"。
Mukul_Dilwaria:
cc := m["k1"]
这里cc的类型是M,相当于interface{},这是一个接口类型。Unmarshal函数的文档说明:
要将JSON解组到接口值中,Unmarshal会在接口值中存储以下类型之一:
bool,对应JSON布尔值 float64,对应JSON数字 string,对应JSON字符串 []interface{},对应JSON数组 map[string]interface{},对应JSON对象 nil,对应JSON null
由于您正在将JSON解组到接口类型中,并且要解组的JSON值({"c": 22})是一个JSON对象,因此结果类型如文档所述是map[string]interface{}。
问题在于您使用了空接口interface{}(在代码中定义为M)来存储不同类型的结构体值。当JSON解组时,Go无法知道原始类型信息,因此会将数据解析为map[string]interface{}而不是原始结构体类型。
以下是修正后的代码:
package main
import (
"encoding/json"
"fmt"
"log"
)
type X struct {
A int `json:"a,omitempty"`
C int `json:"c,omitempty"`
}
type Y struct {
B int
}
func main() {
// 方法1:使用类型断言
m := map[string]interface{}{"k1": X{A: 33}, "k2": Y{B: 2}}
data := `{"c": 22}`
// 获取k1的值并进行类型断言
if x, ok := m["k1"].(X); ok {
err := json.Unmarshal([]byte(data), &x)
if err != nil {
log.Fatal(err)
}
fmt.Printf("方法1结果: %#v\n", x)
m["k1"] = x
}
log.Println("方法1 map:", m)
// 方法2:重新创建结构体实例
m2 := map[string]interface{}{"k1": X{A: 33}, "k2": Y{B: 2}}
var x2 X
x2 = m2["k1"].(X) // 类型断言
err := json.Unmarshal([]byte(data), &x2)
if err != nil {
log.Fatal(err)
}
m2["k1"] = x2
fmt.Printf("方法2结果: %#v\n", x2)
log.Println("方法2 map:", m2)
// 方法3:使用自定义解组逻辑
m3 := map[string]interface{}{"k1": X{A: 33}, "k2": Y{B: 2}}
switch v := m3["k1"].(type) {
case X:
err := json.Unmarshal([]byte(data), &v)
if err != nil {
log.Fatal(err)
}
m3["k1"] = v
fmt.Printf("方法3结果: %#v\n", v)
default:
fmt.Printf("未知类型: %T\n", v)
}
log.Println("方法3 map:", m3)
}
输出结果:
方法1结果: main.X{A:33, C:22}
2009/11/10 23:00:00 方法1 map: map[k1:{33 22} k2:{2}]
方法2结果: main.X{A:33, C:22}
2009/11/10 23:00:00 方法2 map: map[k1:{33 22} k2:{2}]
方法3结果: main.X{A:33, C:22}
2009/11/10 23:00:00 方法3 map: map[k1:{33 22} k2:{2}]
关键点:
- 当使用空接口存储值时,JSON解组会丢失原始类型信息
- 需要使用类型断言来获取具体的结构体类型
- 解组操作必须在具体的类型实例上进行,而不是接口类型
在您的原始代码中,cc是interface{}类型,JSON解组时Go会创建一个新的map[string]interface{}来存储数据,而不是更新原始的X结构体。

