前往地图和界面{}

I have a question regarding the legality of the following statements in go. Why can't I directly convert these two types?

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)  //
}

This code compiles, but when running, you get the panic

panic: interface conversion: main.xtype is map[string]interface {}, not main.ytype

Can somebody explain why this is panics? Clearly they are of the same type in this case. Is it possible to do this kind of direct conversion in Go?

Edit

While is is a contrived example, this does come up in the real world. For example, Cloud Firestore's (part of Firebase) Go library returns maps from the database as map[string]interface{}, no matter how many levels deep they go. So this would be really handy to convert directly into the destination type

You're trying to implicitly convert a nested interface, which doesn't work. x is of type interface{}, and holds, according to your structure, a map[string]interface{}. The interfaces contained within that map then each hold a map[string]interface{}, and those final interfaces each holds a bool. You can't convert an interface{map[string]interface{}{map[string]interface{}{bool}} to a map[string]map[string]bool in a single shot, because that requires unwrapping both the outer interface (the one held by x), each of the inner interfaces in the map, and then each of the interfaces holding the bools in each of the those inner maps. Since there can be more than one key in each level of map, this is an O(n) operation (actually, closer to an O(n*m)), and interface conversions are specifically designed so you can't single-line O(n) conversions.

If you specifically unwrap each layer, and only try to unwrap a single interface at a time, it works just fine. On a side note, you can use fmt.Printf("%#v", <var>) to print explicit type information about the variable in question.

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
", x) // map[string]interface {}{"foo":map[string]interface {}{"bar":true}}

    mid := x.(map[string]interface{})
    fmt.Printf("%#v
", 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
", y) // map[string]map[string]bool{"foo":map[string]bool{"bar":true}}
}