英文:
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")
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论