如何从字符串表示形式的变量中获取嵌套结构?

时间:2018-08-14 12:11:40

标签: json go

我有一个以某种方式关注的JSON文件

{
    "type": "Weekly",
    "clients": [
        "gozo",
        "dva"
    ],
    "sender": "no-reply@flowace.in",
    "recipients": {
        "gozo": [
            "a@gmail.com",
            "b@hotmail.com"
        ],
        "dva": [
            "c@gmail.com",
            "d@hotmail.com"
        ]
    },
    "features": [
        "Top5UsedApps",
        "TimeSpentOnEachL3",
        "NewlyAssignedL3",
        "HoursLogged"
    ],
    "dbCloning": [
        "dva"
    ] 
}

我已经映射了如下结构。

type receivers struct {
    Gozo []string `json:"gozo"`
    Dva  []string `json:"dva"`
    // Add more recievers
}

// Config -- The config object parsed from the JSON file
type Config struct {
    ReportType string    `json:"type"`
    Clients    []string  `json:"clients"`
    Sender     string    `json:"sender"`
    Recipients receivers `json:"recipients"`
    Cloning    []string  `json:"dbCloning"`
}

然后在另一个源文件中的某个位置执行以下操作

func main() {
    conf := LoadConfig(os.Args[1])
    for _, client := range conf.Clients {

        // Use the client variable of some other function calls

        fmt.Println(conf.Recipients[client]) // This will not work
}

现在我的问题是如何使它工作。我无法直接遍历conf.Recipients

PS:请考虑使用LoadConfig函数解组JSON并返回一个conf对象。

编辑1:似乎是设计决策错误。现在使用map[string][]string的解决方案。但是,不要将其标记为答案,因为需要知道在没有其他选择的所有情况下,如何轻松地做到这一点。

2 个答案:

答案 0 :(得分:4)

问题是您的类型receivers不应具有命名字段。它应该是map[string][]string

这是一个有效的示例:

package main

import (
    "encoding/json"
    "fmt"
)

type Config struct {
    ReportType string              `json:"type"`
    Clients    []string            `json:"clients"`
    Sender     string              `json:"sender"`
    Recipients map[string][]string `json:"recipients"`
    Cloning    []string            `json:"dbCloning"`
}

var data = []byte(`{
    "type": "Weekly",
    "clients": [
        "gozo",
        "dva"
    ],
    "sender": "no-reply@flowace.in",
    "recipients": {
        "gozo": [
            "a@gmail.com",
            "b@hotmail.com"
        ],
        "dva": [
            "c@gmail.com",
            "d@hotmail.com"
        ]
    },
    "features": [
        "Top5UsedApps",
        "TimeSpentOnEachL3",
        "NewlyAssignedL3",
        "HoursLogged"
    ],
    "dbCloning": [
        "dva"
    ] 
}`)

func main() {
    var conf Config
    json.Unmarshal(data, &conf)

    for _, client := range conf.Clients {
        fmt.Println(conf.Recipients[client])
    }
}

提供输出

[a@gmail.com b@hotmail.com]
[c@gmail.com d@hotmail.com]

答案 1 :(得分:0)

范围子句提供了一种遍历数组,切片,字符串,映射或通道的方法。因此,在将struct转换为上述类型之一之前,您不能在struct上扩展。

要遍历struct字段,可以通过为struct创建一个反射值切片来进行反射。

package main

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

type receivers struct {
    Gozo []string `json:"gozo"`
    Dva  []string `json:"dva"`
    // Add more recievers
}

// Config -- The config object parsed from the JSON file
type Config struct {
    ReportType string    `json:"type"`
    Clients    []string  `json:"clients"`
    Sender     string    `json:"sender"`
    Recipients receivers `json:"recipients"`
    Cloning    []string  `json:"dbCloning"`
}

var data = []byte(`{
    "type": "Weekly",
    "clients": [
        "gozo",
        "dva"
    ],
    "sender": "no-reply@flowace.in",
    "recipients": {
        "gozo": [
            "a@gmail.com",
            "b@hotmail.com"
        ],
        "dva": [
            "c@gmail.com",
            "d@hotmail.com"
        ]
    },
    "features": [
        "Top5UsedApps",
        "TimeSpentOnEachL3",
        "NewlyAssignedL3",
        "HoursLogged"
    ],
    "dbCloning": [
        "dva"
    ] 
}`)

func main() {
    var conf Config
    if err := json.Unmarshal(data, &conf); err != nil{
        fmt.Println(err)
    }

    v := reflect.ValueOf(conf.Recipients)

    values := make([]interface{}, v.NumField())

    for i := 0; i < v.NumField(); i++ {
        values[i] = v.Field(i).Interface()
    }

    fmt.Println(values)
}

Go Playground上的工作代码

  

NumField返回struct v中的字段数。   v的种类不是结构。

func (v Value) NumField() int
  

Field返回结构的第i个字段   v。如果v的Kind不是Struct或i超出范围,它会感​​到恐慌。

func (v Value) Field(i int) Value

接口返回v的当前值作为接口{}。

func (v Value) Interface() (i interface{})