关于多种结构数据的赋值和取值

0. 问题开始

早上刚上班没多久,zn就发过来一个消息:

map[type:[any_type]]

然后过来问我:怎么能遍历到type里的值?

zn是写Python的,我是写web前端的——偶然间闲聊发现彼此都在尝试学习Go,有的时候遇到问题就相互探讨一下了——这个用Python和JS写都是再简单不过的事情,不过遇到强类型的Go,就傻眼了。

于是我就到zn的工位与他一起研究起来,然而不是自己的编辑器,怎么看都觉得不太对,况且这个内容是一个函数中的一段,看着比较繁冗,我就提议把数据单独提出来测试。

1. 新的问题

zn原来的代码是照着参考自己摸索着写的,原数据貌似是JSON字符串转换而来,当我提到新建一个文件来测试,却发现赋值也有难度:

{
  "info": {
    "type": [
"group"
] }, "id": 2873 }

zn直接 info := {"info": {"type": ["group"]}, "id": 2873} 这自然是不行的。

而且我发现,zn原来用的类型是 map[]interface{} ,这让我有点发懵,在zn把字符串发给我以后,我回到自己的工位上琢磨这个该怎么写。

2. 一个思路

我把原来对着Runoob的教程写的例子翻出来看看,从赋值开始,赋值成功之后开始取值、打印,过程略,直接贴代码吧。

// InfoData 信息数据结构体
type InfoData struct {
    info  map[string][]string
    id int16
}

func infoTest() {
    var fileInfo map[string][]string
    fileInfo = make(map[string][]string)
    fileInfo["type"] = []string{"any_type"}
    var info InfoData = InfoData{info: fileInfo, id: 1234}
    fmt.Printf("info:%#v\n", info)
    fmt.Printf("fileInfo:%#v\n", info.info)
    for _, v := range info.info["type"] {
        fmt.Println("v:", v)
    }
}

我自作主张把原来的最外层的 map 改成了 struct ,而zn原本的逻辑是遍历 map ,判断类型,如果是数组或切片,再进行遍历,而我改成结构体以后,就不能进行遍历了,很明显这有悖初衷。

而且,从数据库过来的数据本来就是 map[]interface{} 类型,并不是自己写成的数据,好吧,这就是没有实战经验的菜鸟所踏的坑。

明白了这些,开始重新写。

3. 解决方案

func main() {
    data := map[string]interface{}{
        "id":   5678,
        "name": "big plan",
        "info": map[string]interface{}{
            "type": []interface{}{
                "group",
                "unit",
            },
        },
    }
    loopData(data)
}

func loopData(data interface{}) {
    if content, ok := data.(map[string]interface{}); ok {
        // 注意,这里一定要取断言后的值进行 for range
        // 不然的话会因为 data 本身是 interface{} 而报错
        for k, v := range content {
            if val, ok := v.(string); ok {
                fmt.Printf("%v: %q\n", k, val)
            } else if val, ok := v.(int); ok {
                fmt.Printf("%v: %v\n", k, val)
            } else if val, ok := v.(map[string]interface{}); ok {
                loopData(val)
            } else if val, ok := v.([]interface{}); ok {
                loopData(val)
            } else {
                fmt.Printf("type of %v is %T\n", k, v)
            }
        }
    } else if content, ok := data.([]interface{}); ok {
        for i, val := range content {
            fmt.Printf("type%d: %q\n", i+1, val)
        }
    }
}

打印结果:

id: 5678
name: "big plan"
type1: "group"
type2: "unit"

基本就是这样,算是完成了需求。

4. 后记

这本来是2020年9月份的一件事,为了记录这个长长路上的一次低级扑街还特地申请了博客园的写作权限,却只写了一半就丢下了。

当时间来到2021年1月份,想起这件事情,回头看过去也挺可笑的,还是来结个尾,也算是一个happy ending吧。

祝2021年大家都好。

posted @ 2021-01-08 18:03  鲤白  阅读(177)  评论(0)    收藏  举报