【问题标题】:Go maps and interface{}Go 地图和界面{}
【发布时间】:2018-04-07 20:03:29
【问题描述】:

我对 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 is map[string]interface {}, not main.ytype

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

编辑

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

【问题讨论】:

标签: go types type-conversion


【解决方案1】:

您正在尝试隐式转换嵌套接口,但这是行不通的。 xinterface{} 类型,并且根据您的结构,拥有 map[string]interface{}。该映射中包含的接口每个都包含一个map[string]interface{},而这些最终接口每个都包含一个布尔值。您不能一次将interface{map[string]interface{}{map[string]interface{}{bool}} 转换为map[string]map[string]bool,因为这需要解开外部接口(@98​​7654328@ 持有的接口)、映射中的每个内部接口,然后是每个在每个内部映射中保存布尔值的接口。由于每一层map中可以有多个key,所以这是一个O(n)操作(实际上更接近一个O(n*m)),并且接口转换是专门设计的你不能单行 O(n) 转换。

如果您专门解开每一层,并且一次只尝试解开一个界面,它就可以正常工作。附带说明一下,您可以使用 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}}
}

【讨论】:

    猜你喜欢
    • 2016-01-19
    • 2014-01-14
    • 2011-09-12
    • 2021-12-23
    • 1970-01-01
    • 1970-01-01
    • 2016-09-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多