Go映射和接口{}

Go映射和接口{},go,types,type-conversion,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{}{ "

我对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 conversion:main.xtype是map[string]接口{},而不是main.ytype

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

编辑
虽然这是一个人为的例子,但在现实世界中确实会出现。例如,Cloud Firestore的(Firebase的一部分)Go库以
map[string]接口{}
的形式从数据库返回地图,不管它们有多深。因此,如果您试图隐式转换嵌套接口,那么直接将其转换为目标类型将非常方便
x
属于
interface{}
类型,根据您的结构,它包含一个
map[string]interface{}
。然后,该映射中包含的接口各自持有一个
map[string]接口{}
,而这些最终接口各自持有一个bool。不能在一次快照中将
接口{map[string]接口{}{map[string]接口{}{bool}
转换为
map[string]map[string]bool
,因为这需要同时打开外部接口(由
x
持有的接口),映射中的每个内部接口,然后是每个内部映射中保存布尔值的每个接口。由于每个映射级别中可能有多个键,所以这是一个O(n)操作(实际上,更接近O(n*m)),并且接口转换是专门设计的,所以您不能进行单行O(n)转换

如果您专门展开每一层,并且一次只尝试展开一个接口,那么它可以正常工作。另外,您可以使用
fmt.Printf(“%#v”)
打印有关所讨论变量的显式类型信息

请参阅。由于接口{}不是map[string]bool.Duplicate,因此它们显然不是同一类型。
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}}
}