简体   繁体   English

Go 地图和界面{}

[英]Go maps and interface{}

I have a question regarding the legality of the following statements in go.我对 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?是否可以在 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.例如,Cloud Firestore 的(Firebase 的一部分)Go 库以map[string]interface{}从数据库返回地图,无论它们深入多少层。 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{} . xinterface{}类型,并根据您的结构保存一个map[string]interface{} The interfaces contained within that map then each hold a map[string]interface{} , and those final interfaces each holds a bool.该映射中包含的接口每个都包含一个map[string]interface{} ,而这些最终接口每个都包含一个 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.您不能一次将interface{map[string]interface{}{map[string]interface{}{bool}}转换为map[string]map[string]bool ,因为这需要解开两个外部接口(由x持有的那个),映射中的每个内部接口,然后每个接口都持有这些内部映射中的每一个中的布尔值。 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.由于map的每一层可以有多个key,所以这是一个O(n)操作(实际上,更接近于一个O(n*m) ),而且接口转换是专门设计的,所以你不能单行O(n) 转换。

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.附带说明一下,您可以使用fmt.Printf("%#v", <var>)打印有关相关变量的显式类型信息。

https://play.golang.org/p/Ng9CE0O34G 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}}
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM