在Golang中访问类型为map[string]interface{}的嵌套映射可以通过以下方式实现:

huangapple go评论85阅读模式
英文:

Accessing Nested Map of Type map[string]interface{} in Golang

问题

所以我正在尝试解析一个JSON响应。它可以是多层嵌套的。这是我做的:

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

首先,这样做对吗?

假设响应如下:

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

为了访问键foo,我在一个playground上看到了这样的写法:

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

在这里,.()表示什么意思?这样写对吗?

英文:

So I'm trying to parse a JSON response. It can be multiple levels deep. This is what I did:

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

Firstly, is this the right way to do it?

Lets say the response was as follows:

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

To access key foo, I saw a playground doing this:

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

Here, what is the .() notation? Is this correct?

答案1

得分: 57

符号x.(T)被称为类型断言

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

你的例子:

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

这意味着你的results映射中与键"args"关联的值是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)
英文:

The notation x.(T) is called a Type Assertion.

> For an expression x of interface type and a type T, the primary expression x.(T) asserts that x is not nil and that the value stored in x is of type T.

Your example:

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

It means that the value of your results map associated with key "args" is of type map[string]interface{} (another map with string keys and any values). And you want to access the element of that map associated with the key "foo".

If you know noting about the input JSON format, then yes, you have to use a generic map[string]interface{} type to process it. If you know the exact structure of the input JSON, you can create a struct to match the expected fields, and doing so you can unmarshal a JSON text into a value of your custom struct type, for example:

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)
}

Output:

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

Try it on the Go Playground.

Modeling your input

Your current JSON input could be modelled with this type:

type Data struct {
    Args struct {
        Foo string
    }
}

And accessing Foo (try it on the Go Playground):

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

答案2

得分: 10

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

英文:

struct is the best option, but if you insist, you can add a type declaration for a map, then you can add methods to help
with the type assertions:

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

huangapple
  • 本文由 发表于 2015年3月2日 18:00:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/28806951.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定