Golang中如何将Interface{}转换为Struct

Golang中如何将Interface{}转换为Struct 你好,

我将一个 JSON 文件(见下方示例)加载到一个通用的 interface{} 对象中,并希望将其转换为一个正式的结构体。我的问题是,'properties''help''properties' 数组会不断重复,直到子 'help' 数组为 NULL,而我们事先并不知道这一点。

{
    "list": {
        "lstexampleA": [
            { "properties": [
                    {
                        "with": "OPTION1",
                        "help": [
                            {
                                "properties": [
                                    {   
                                        "with": null, 
                                        "help": null,
                                        "element": "MP0001"
                                    }
                                ]
                            },
                            {
                                "properties": [
                                    { 
                                        "with": null, 
                                        "help": null,  
                                        "element": "MP0002"
                                    }
                                ]                                           
                            }
                        ]
                    },
                    { 
                        "with": "OPTION6",
                        "help": null,
                        "element": 10
                    } 
                ],
                "element": 100
            }
        ],
        "lstexampleB": [ .....

        ]
    }
}

所以,也许需要类似这样的结构…

var olists []oList

type oList struct {
	OWith     string
	OHelp     []oList
    OElement  interface{}
}

是否有标准的方法来遍历 interface{} 对象,并在遍历过程中构建结构体…

谢谢


更多关于Golang中如何将Interface{}转换为Struct的实战教程也可以访问 https://www.itying.com/category-94-b0.html

4 回复

@christophberger。非常感谢。对我来说效果非常好。

更多关于Golang中如何将Interface{}转换为Struct的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


完美!很高兴听到它在你的场景中运行良好。

你好 @Steff,欢迎来到论坛。

json.Unmarshall 可以处理相同类型的嵌套数据。 要让 Unmarshal() 在 Go 中构建嵌套结构体,请使用指针来描述子结构体:

var lists []List

type List struct {
	With     string
	Help     []oList
    Element  *List
}

我修改了 Unmarshal 文档中的示例 来解析嵌套的 Animal 数据作为概念验证:

var jsonBlob = []byte(`[
	{"Name": "Platypus", "Order": "Monotremata", "Animal": 
		{"Name": "Plotypas", "Order": "Manatremoto", "Animal":
			{"Name": "Plytapos", "Order": "Menetromata" }
		}
	},
	{"Name": "Quoll", "Order": "Dasyuromorphia"}
]`)
	type Animal struct {
		Name   string
		Order  string
		Animal *Animal
	}
	var animals []Animal
	err := json.Unmarshal(jsonBlob, &animals)
	if err != nil {
		fmt.Println("error:", err)
	}
	spew.Dump(animals)

完整、可运行的代码可在 Playground 中找到。

输出(确实,spew.Dump() 在这里可能有点过于冗长,只需看整体结构而不是细节):

([]main.Animal) (len=2 cap=4) {
 (main.Animal) {
  Name: (string) (len=8) "Platypus",
  Order: (string) (len=11) "Monotremata",
  Animal: (*main.Animal)(0xc0000a05a0)({
   Name: (string) (len=8) "Plotypas",
   Order: (string) (len=11) "Manatremoto",
   Animal: (*main.Animal)(0xc0000a05d0)({
    Name: (string) (len=8) "Plytapos",
    Order: (string) (len=11) "Menetromata",
    Animal: (*main.Animal)(<nil>)
   })
  })
 },
 (main.Animal) {
  Name: (string) (len=5) "Quoll",
  Order: (string) (len=14) "Dasyuromorphia",
  Animal: (*main.Animal)(<nil>)
 }
}

在Go语言中,处理这种嵌套不确定深度的JSON数据,可以使用递归和类型断言。以下是完整的解决方案:

package main

import (
	"encoding/json"
	"fmt"
)

// 定义结构体
type OList struct {
	OWith    string   `json:"with"`
	OHelp    []OList  `json:"help"`
	OElement any      `json:"element"`
}

// 递归解析函数
func parseProperties(data any) []OList {
	var result []OList
	
	// 类型断言检查是否为slice
	if slice, ok := data.([]any); ok {
		for _, item := range slice {
			if itemMap, ok := item.(map[string]any); ok {
				olist := OList{}
				
				// 解析with字段
				if withVal, ok := itemMap["with"].(string); ok {
					olist.OWith = withVal
				} else if withVal, ok := itemMap["with"]; ok && withVal == nil {
					olist.OWith = ""
				}
				
				// 解析element字段
				olist.OElement = itemMap["element"]
				
				// 递归解析help字段
				if helpVal, ok := itemMap["help"]; ok && helpVal != nil {
					if helpSlice, ok := helpVal.([]any); ok && len(helpSlice) > 0 {
						for _, helpItem := range helpSlice {
							if helpMap, ok := helpItem.(map[string]any); ok {
								if props, ok := helpMap["properties"]; ok {
									olist.OHelp = append(olist.OHelp, parseProperties(props)...)
								}
							}
						}
					}
				}
				
				result = append(result, olist)
			}
		}
	}
	
	return result
}

func main() {
	// 示例JSON数据
	jsonData := `{
		"list": {
			"lstexampleA": [
				{
					"properties": [
						{
							"with": "OPTION1",
							"help": [
								{
									"properties": [
										{
											"with": null,
											"help": null,
											"element": "MP0001"
										}
									]
								},
								{
									"properties": [
										{
											"with": null,
											"help": null,
											"element": "MP0002"
										}
									]
								}
							]
						},
						{
							"with": "OPTION6",
							"help": null,
							"element": 10
						}
					],
					"element": 100
				}
			]
		}
	}`

	// 解析JSON到interface{}
	var data map[string]any
	if err := json.Unmarshal([]byte(jsonData), &data); err != nil {
		panic(err)
	}

	// 获取list.lstexampleA[0].properties
	listData, _ := data["list"].(map[string]any)
	lstexampleA, _ := listData["lstexampleA"].([]any)
	firstItem, _ := lstexampleA[0].(map[string]any)
	properties, _ := firstItem["properties"].([]any)

	// 递归解析
	olists := parseProperties(properties)

	// 打印结果
	fmt.Printf("解析出 %d 个OList:\n", len(olists))
	for i, item := range olists {
		fmt.Printf("\n[%d] With: %s, Element: %v\n", i, item.OWith, item.OElement)
		if len(item.OHelp) > 0 {
			fmt.Printf("  包含 %d 个子项:\n", len(item.OHelp))
			for j, child := range item.OHelp {
				fmt.Printf("    [%d] With: %s, Element: %v\n", j, child.OWith, child.OElement)
			}
		}
	}
}

输出结果:

解析出 2 个OList:

[0] With: OPTION1, Element: <nil>
  包含 2 个子项:
    [0] With: , Element: MP0001
    [1] With: , Element: MP0002

[1] With: OPTION6, Element: 10

这个解决方案的关键点:

  1. 递归函数parseProperties 函数会递归调用自身来处理嵌套的 helpproperties 结构
  2. 类型断言:使用 .(type) 语法来检查 interface{} 的实际类型
  3. 空值处理:正确处理JSON中的 null
  4. 灵活的类型OElement 使用 any(Go 1.18+)或 interface{} 来容纳不同类型的值

如果需要处理整个JSON结构(包括外层的list和lstexampleA等),可以扩展这个递归函数来遍历整个数据结构。

回到顶部