douyue8685 2012-06-05 14:51
浏览 34
已采纳

理解Go中`interface {}`用法的问题

I'm trying to port an algorithm from Python to Go. The central part of it is a tree built using dicts, which should stay this way since each node can have an arbitrary number of children. All leaves are at the same level, so up the the lowest level the dicts contain other dicts, while the lowest level ones contain floats. Like this:

tree = {}
insert(tree, ['a', 'b'], 1.0)
print tree['a']['b']

So while trying to port the code to Go while learning the language at the same time, this is what I started with to test the basic idea:

func main() {
    tree := make(map[string]interface{})
    tree["a"] = make(map[string]float32)
    tree["a"].(map[string]float32)["b"] = 1.0
    fmt.Println(tree["a"].(map[string]float32)["b"])
}

This works as expected, so the next step was to turn this into a routine that would take a "tree", a path, and a value. I chose the recursive approach and came up with this:

func insert(tree map[string]interface{}, path []string, value float32) {
    node := path[0]
    l := len(path)
    switch {
    case l > 1:
        if _, ok := tree[node]; !ok {
            if l > 2 {
                tree[node] = make(map[string]interface{})
            } else {
                tree[node] = make(map[string]float32)
            }
        }
        insert(tree[node], path[1:], value) //recursion
    case l == 1:
        leaf := tree
        leaf[node] = value
    }
}

This is how I imagine the routine should be structured, but I can't get the line marked with "recursion" to work. There is either a compiler error, or a runtime error if I try to perform a type assertion on tree[node]. What would be the correct way to do this?

  • 写回答

2条回答 默认 最新

  • duanli0453 2012-06-05 15:22
    关注

    Go is perhaps not the ideal solution for generic data structures like this. The type assertions make it possible, but manipulating data in it requires more work that you are used to from python and other scripting languages.

    About your specific issue: You are missing a type assertion in the insert() call. The value of tree[node] is of type interface{} at that point. The function expects type map[string]interface{}. A type assertion will solve that.

    Here's a working example:

    package main
    
    import "fmt"
    
    type Tree map[string]interface{}
    
    func main() {
        t := make(Tree)
        insert(t, []string{"a", "b"}, 1.0)
    
        v := t["a"].(Tree)["b"]
        fmt.Printf("%T %v
    ", v, v)
    
        // This prints: float32 1
    }
    
    func insert(tree Tree, path []string, value float32) {
        node := path[0]
        len := len(path)
    
        switch {
        case len == 1:
            tree[node] = value
    
        case len > 1:
            if _, ok := tree[node]; !ok {
                tree[node] = make(Tree)
            }
    
            insert(tree[node].(Tree), path[1:], value) //recursion
        }
    }
    

    Note that I created a new type for the map. This makes the code a little easier to follow. I also use the same 'map[string]interface{}` for both tree nodes and leaves. If you want to get a float out of the resulting tree, another type assertion is needed:

    leaf := t["a"].(Tree)["b"]  // leaf is of type 'interface{}`.
    val := leaf.(float32)
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥30 这是哪个作者做的宝宝起名网站
  • ¥60 版本过低apk如何修改可以兼容新的安卓系统
  • ¥25 由IPR导致的DRIVER_POWER_STATE_FAILURE蓝屏
  • ¥50 有数据,怎么建立模型求影响全要素生产率的因素
  • ¥50 有数据,怎么用matlab求全要素生产率
  • ¥15 TI的insta-spin例程
  • ¥15 完成下列问题完成下列问题
  • ¥15 C#算法问题, 不知道怎么处理这个数据的转换
  • ¥15 YoloV5 第三方库的版本对照问题
  • ¥15 请完成下列相关问题!