go - 如何在接口(interface)上调用 len()?

标签 go

我正在编写一个 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 :

panic: interface conversion: interface is []interface {}, not []string [recovered]

我想在这里写什么?

最佳答案

在 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 中表示它们的数据结构称为“slice ”(Go 也有数组,但它们是独立的东西——如果你习惯于 C 或 Java 等语言中的数组,Go slice 是最接近的类似物)。

关于go - 如何在接口(interface)上调用 len()?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21070387/

相关文章:

go - cgo:将 `[]uchar`转换为 `[]byte`

go - 将 slice 附加到函数参数的 slice

go - 为什么长度为 512 的缓冲区字节数组,又名 [512]byte 在 Go 中更适合读写?

mysql - 如何将 JSON 对象转换为 MySQL 行?

go - 解码 JSON 时接受 proto 结构中的动态键

go - fabric-sdk-go 'ld.exe: cannot find -lltdl' 错误

docker - 我尝试在 docker 中部署 gRPC (go) 服务器并在本地端口中公开端口,但端口绑定(bind)不起作用

reactjs - 如何在客户端隐藏 firebaseConfig 信息

go - 如何打印 os.args[1 :] without braces in Go?

go - 在同一行打印多行字符串