Go map 和界面{}

标签 go types type-conversion

我对以下go语句的合法性有疑问。为什么我不能直接转换这两种类型?

package main

import (
    "fmt"
)

type xtype interface{}
type ytype map[string]map[string]bool

func main() {
    myvar := map[string]xtype{
        "x": map[string]interface{}{
            "foo": map[string]interface{}{
                "bar": true,
            },
        },
    }
    x := myvar["x"] // x is of type 'xtype'
    fmt.Println(x)  // Prints map[foo:map[bar:true]]
    y := x.(ytype)  // Panic
    fmt.Println(y)  //
}

这段代码可以编译,但是在运行时,你会遇到 panic

紧急:接口(interface)转换:main.xtype 是 map[string]interface {},不是 main.ytype

有人可以解释为什么这是 panic 吗?显然,在这种情况下它们属于同一类型。是否可以在 Go 中进行这种直接转换?

编辑

虽然这是一个人为的例子,但这确实出现在现实世界中。例如,Cloud Firestore 的(Firebase 的一部分)Go 库以 map[string]interface{} 的形式从数据库返回 map ,无论 map 有多深。所以直接转换成目标类型真的很方便

最佳答案

您正在尝试隐式转换嵌套接口(interface),但这行不通。 x类型为 interface{} ,并根据您的结构持有 map[string]interface{} .该映射中包含的接口(interface)每个都包含一个 map[string]interface{}。 ,而那些最终的接口(interface)每个都有一个 bool 值。您无法转换 interface{map[string]interface{}{map[string]interface{}{bool}}map[string]map[string]bool在一次拍摄中,因为这需要展开外部接口(interface)(由 x 持有的接口(interface))、映射中的每个内部接口(interface),然后是每个内部映射中包含 bool 值的每个接口(interface)。由于在每一级映射中可以有多个键,这是一个 O(n) 操作(实际上,更接近于 O(n*m)),并且接口(interface)转换是专门设计的,因此你不能单行 O(n) 转换。

如果你专门解包每一层,并且一次只尝试解包一个接口(interface),它工作得很好。在旁注中,您可以使用 fmt.Printf("%#v", <var>)打印有关变量的显式类型信息。

https://play.golang.org/p/Ng9CE0O34G

package main

import (
    "fmt"
)

type xtype interface{}
type ytype map[string]map[string]bool

func main() {
    myvar := map[string]xtype{
        "x": map[string]interface{}{
            "foo": map[string]interface{}{
                "bar": true,
            },
        },
    }

    x := myvar["x"]        // x is of type 'xtype'
    fmt.Printf("%#v\n", x) // map[string]interface {}{"foo":map[string]interface {}{"bar":true}}

    mid := x.(map[string]interface{})
    fmt.Printf("%#v\n", mid) // map[string]interface {}{"foo":map[string]interface {}{"bar":true}}

    y := make(map[string]map[string]bool)
    for k, v := range mid {
        m := make(map[string]bool)
        for j, u := range v.(map[string]interface{}) {
            m[j] = u.(bool)
        }
        y[k] = m
    }
    fmt.Printf("%#v\n", y) // map[string]map[string]bool{"foo":map[string]bool{"bar":true}}
}

关于Go map 和界面{},我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46954314/

相关文章:

c++ - 无法使用 Nlohmann 的 JSON 获取对象内部的 vector

mysql - 如何在MySQL中将位掩码应用于整数?

xml - Golang : get inner xml from xml with xml.解码

python - 确定变量的类型是 python 中的 NoneType

ios - ARC-Type 转换导致编译错误

mysql - mysql 5.5 上的 joomla 1.5.22

types - 为什么要在Julia中创建抽象父类(super class)型?

templates - 模板不呈现任何内容,也没有错误,但是状态为200

go - goroutine 和 channel 通信的奇怪行为

go - 无法使用基本身份验证保护 gorilla/mux 子路由