我正在尝试将算法从Python移植到Go。它的核心部分是使用dicts构建的树,它应该保持这种方式,因为每个节点可以有任意数量的子节点。所有叶子都处于同一水平,所以最高水平的dicts包含其他dicts,而最低水平的叶子包含浮动。像这样:
tree = {}
insert(tree, ['a', 'b'], 1.0)
print tree['a']['b']
因此,在尝试将代码移植到Go同时学习语言的同时,这就是我开始测试基本思想的原因:
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"])
}
这可以按预期工作,因此下一步是将其转换为一个采用“树”,路径和值的例程。我选择了递归方法并想出了这个:
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
}
}
这就是我想象的例程应该是如何构建的,但我不能让标有“递归”的行工作。如果我尝试在tree[node]
上执行类型断言,则会出现编译器错误或运行时错误。这样做的正确方法是什么?
答案 0 :(得分:7)
关于您的具体问题:您在insert()
电话中缺少类型断言。此时tree[node]
的值为interface{}
类型。该函数需要类型map[string]interface{}
。类型断言将解决这个问题。
这是一个有效的例子:
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\n", 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
}
}
请注意,我为地图创建了一个新类型。这使代码更容易遵循。我也对树节点和叶子使用相同的'map [string] interface {}`。如果要从结果树中获取浮点数,则需要另一种类型的断言:
leaf := t["a"].(Tree)["b"] // leaf is of type 'interface{}`.
val := leaf.(float32)
答案 1 :(得分:6)
我不会使树成为显式地图[string] interface {}。树和树上的节点实际上是一回事,因为它是递归数据类型。
type Tree struct {
Children []*Tree
Value interface{}
}
func NewTree(v interface{}) *Tree {
return &Tree{
Children: []*Tree{},
Value: v,
}
}
所以要加个孩子......
func (t *Tree) AddChild(child interface{}) {
switch c := child.(type) {
case *Tree:
t.Children = append(t.Children, c)
default:
t.Children = append(t.Children, NewTree(c))
}
}
如果你想实现一些递归函数......
func (t *Tree) String() string {
return fmt.Sprint(t.Value)
}
func (t *Tree) PrettyPrint(w io.Writer, prefix string) {
var inner func(int, *Tree)
inner = func(depth int, child *Tree) {
for i := 0; i < depth; i++ {
io.WriteString(w, prefix)
}
io.WriteString(w, child.String()+"\n") // you should really observe the return value here.
for _, grandchild := range child.Children {
inner(depth+1, grandchild)
}
}
inner(0, t)
}
这样的事情。任何节点都可以成为某个树的根,因为子树本身就是一棵树。请参阅此处查看工作示例:http://play.golang.org/p/rEx43vOnXN
有一些文章像“Python不是Java”(http://dirtsimple.org/2004/12/python-is-not-java.html),为此,Go不是Python。