如何在界面上调用len()?

Kev*_*rke 9 go

我正在编写一个JSON列表为空的测试.

{"matches": []}
Run Code Online (Sandbox Code Playgroud)

对象有类型map[string]interface{},我想测试列表是否为空.

var matches := response["matches"]
if len(matches) != 0 {
    t.Errorf("Non-empty match list!")
}
Run Code Online (Sandbox Code Playgroud)

但是我在编译时告诉我这是无效的

invalid argument matches (type interface {}) for len
Run Code Online (Sandbox Code Playgroud)

如果我尝试转换为列表类型:

matches := response["matches"].([]string)
Run Code Online (Sandbox Code Playgroud)

我感到恐慌:

panic: interface conversion: interface is []interface {}, not []string [recovered]
Run Code Online (Sandbox Code Playgroud)

我想在这里写些什么?

jos*_*hlf 18

使用Go中的映射进行JSON解析时,无处不在使用接口.想象一下,你有以下JSON对象:

{
    "stuff" : [
        "stuff1",
        "stuff2",
        "stuff3",
    ]
}
Run Code Online (Sandbox Code Playgroud)

Go JSON库将外部对象解析为从键到值的映射,正如您在代码中看到的那样.它将变量名称映射为与这些变量名称对应的值的键.但是,由于它无法提前知道这些值什么,因此地图的值类型很简单interface{}.所以,假设您知道有一个被调用的密钥"stuff",并且您知道它的值是一个数组.你可以这样做:

arr := myMap["stuff"]
Run Code Online (Sandbox Code Playgroud)

而且你知道它是一个数组类型,所以你实际上可以这样做:

arr := myMap["stuff"].([]interface{})
Run Code Online (Sandbox Code Playgroud)

这里的问题是,虽然你是对的,它是一个数组,而JSON库知道这一点,它无法知道每个元素都是类型的string,所以没有办法让它决定数组类型应该是是[]string.想象一下,如果你这样做了:

{
    "stuff" : [
        "stuff1",
        "stuff2",
        3
    ]
}
Run Code Online (Sandbox Code Playgroud)

好吧"stuff"现在不能是一个字符串数组,因为其中一个元素不是字符串.事实上,它不能是任何东西的数组- 没有一种类型可以满足所有元素的类型.这就是为什么Go JSON库别无选择,只能将其保留为[]interface{}.幸运的是,既然你想要的只是长度,你已经完成了.你可以这样做:

arr := myMap["stuff"].([]interface{})
l := len(arr)
Run Code Online (Sandbox Code Playgroud)

现在这一切都很好,但是让我们说你想要实际看到其中一个元素.您现在可以取出一个元素,并且知道它是一个字符串,执行:

arr := myMap["stuff"].([]interface{})
iv := arr[0] // interface value
sv := iv.(string) // string value
Run Code Online (Sandbox Code Playgroud)

注意

当我说"数组"时,我指的是JSON意义上的数组 - 这些是JSON数组.在Go中表示它们的数据结构称为"切片"(Go也有数组,但它们是一个单独的东西 - 如果您习惯使用C或Java等语言中的数组,则Go切片是最接近的模拟).