我正在编写一个JSON列表为空的测试。
{"matches": []}
对象的类型为map[string]interface{}
,我想测试列表是否为空。
var matches := response["matches"]
if len(matches) != 0 {
t.Errorf("Non-empty match list!")
}
但是我在编译时被告知这是无效的
invalid argument matches (type interface {}) for len
如果我尝试转换为列表类型:
matches := response["matches"].([]string)
我感到恐慌:
panic: interface conversion: interface is []interface {}, not []string [recovered]
我想在这里写些什么?
答案 0 :(得分:14)
使用Go中的地图进行JSON解析时使用无处不在的接口。想象一下,你有以下JSON对象:
{
"stuff" : [
"stuff1",
"stuff2",
"stuff3",
]
}
Go JSON库将外部对象解析为从键到值的映射,正如您在代码中看到的那样。它将变量名称映射为与这些变量名称对应的值的键。但是,由于无法提前知道这些值是,因此地图的值类型只是interface{}
。所以,假设您知道有一个名为"stuff"
的密钥,您知道它的值是一个数组。你可以这样做:
arr := myMap["stuff"]
而且你知道它是一个数组类型,所以你实际上可以这样做:
arr := myMap["stuff"].([]interface{})
这里的问题是,虽然你是对的,它是一个数组,并且JSON库知道这一点,但它无法知道每个元素都是string
类型,所以没有办法确定数组类型实际上应该是[]string
。想象一下,如果你这样做了:
{
"stuff" : [
"stuff1",
"stuff2",
3
]
}
好"stuff"
现在不能是字符串数组,因为其中一个元素不是字符串。实际上,它不能是任何的数组 - 没有一种类型可以满足所有元素的类型。这就是为什么Go JSON库别无选择,只能将其保留为[]interface{}
。幸运的是,既然你想要的只是长度,你已经完成了。你可以这样做:
arr := myMap["stuff"].([]interface{})
l := len(arr)
现在这一切都很好,但是让我们说你想要实际看到其中一个元素。您现在可以取出一个元素,并且知道它是一个字符串,执行:
arr := myMap["stuff"].([]interface{})
iv := arr[0] // interface value
sv := iv.(string) // string value
注意强>
当我说“数组”时,我指的是JSON意义上的数组 - 这些是JSON数组。在Go中表示它们的数据结构称为“切片”(Go也有数组,但它们是一个单独的东西 - 如果您习惯使用C或Java等语言中的数组,则Go切片是最接近的模拟)。
答案 1 :(得分:0)
在处理 JSON 时,我喜欢为 Map 和 Slice 添加类型声明,然后 我可以根据需要添加方法来帮助转换:
package main
import "encoding/json"
type Map map[string]interface{}
type Slice []interface{}
func (m Map) A(s string) Slice {
return m[s].([]interface{})
}
func main() {
y := []byte(`{"matches": []}`)
response := Map{}
json.Unmarshal(y, &response)
matches := response.A("matches")
n := len(matches)
println(n == 0)
}