【问题标题】:Accessing Nested Map of Type map[string]interface{} in Golang在 Golang 中访问 map[string]interface{} 类型的嵌套映射
【发布时间】:2015-05-02 15:17:38
【问题描述】:

所以我正在尝试解析 JSON 响应。它可以是多个级别的深度。这就是我所做的:

var result map[string]interface{}
json.Unmarshal(apiResponse, &result)

首先,这是正确的做法吗?

假设响应如下:

{
  "args": {
            "foo": "bar"
          }
}

要访问密钥foo,我看到playground 这样做:

result["args"].(map[string]interface{})["foo"]

这里,.() 符号是什么?这是正确的吗?

【问题讨论】:

    标签: json dictionary go interface


    【解决方案1】:

    符号x.(T) 称为Type Assertion

    对于接口类型的表达式xT 类型,主表达式x.(T) 断言x 不是nil,并且存储在x 中的值是T 类型.

    你的例子:

    result["args"].(map[string]interface{})["foo"]
    

    这意味着与键 "args" 关联的 results 映射的值是 map[string]interface{} 类型(另一个具有 string 键和任何值的映射)。并且您想访问与键 "foo" 关联的该映射的元素。

    如果您知道输入 JSON 格式,那么是的,您必须使用通用的 map[string]interface{} 类型来处理它。如果您知道输入 JSON 的确切结构,则可以创建一个 struct 来匹配预期字段,然后您可以将 JSON 文本解组为您的自定义 struct 类型的值,例如:

    type Point struct {
        Name string
        X, Y int
    }
    
    func main() {
        in := `{"Name":"center","X":2,"Y":3}`
    
        pt := Point{}
        json.Unmarshal([]byte(in), &pt)
    
        fmt.Printf("Result: %+v", pt)
    }
    

    输出:

    Result: {Name:center X:2 Y:3}
    

    Go Playground 上试用。

    为您的输入建模

    您当前的 JSON 输入可以用这种类型建模:

    type Data struct {
        Args struct {
            Foo string
        }
    }
    

    并访问Foo(在Go Playground) 上尝试:

    d := Data{}
    json.Unmarshal([]byte(in), &d)
    fmt.Println("Foo:", d.Args.Foo)
    

    【讨论】:

    • 另外,如果foo的类型是interface{},那么string(foo)foo.(string)有什么区别?
    • @SreejithRamakrishnan 我认为如果您使用自定义struct 不会对性能造成任何重大影响,它也是通过反射填充的。
    • @SreejithRamakrishnan 是的,stirng(foo)foo.(string) 之间存在差异。第一个是conversion,后者是type assertion。类型断言只能用于接口类型interface{} 是一个符合条件的空接口),转换规则请阅读规范:Conversions。如果您的情况不能使用仅转换类型断言。
    【解决方案2】:

    struct 是最好的选择,但如果你坚持,你可以为 map 添加类型声明,然后你可以添加方法来帮助 使用类型断言:

    package main
    import "encoding/json"
    
    type dict map[string]interface{}
    
    func (d dict) d(k string) dict {
       return d[k].(map[string]interface{})
    }
    
    func (d dict) s(k string) string {
       return d[k].(string)
    }
    
    func main() {
       apiResponse := []byte(`{"args": {"foo": "bar"}}`)
       var result dict
       json.Unmarshal(apiResponse, &result)
       foo := result.d("args").s("foo")
       println(foo == "bar")
    }
    

    https://golang.org/ref/spec#Type_declarations

    【讨论】:

      猜你喜欢
      • 2017-12-11
      • 2021-06-22
      • 2023-04-01
      • 2019-04-02
      • 2016-02-27
      • 2018-10-08
      • 2021-06-11
      • 1970-01-01
      • 2021-01-02
      相关资源
      最近更新 更多