我正在尝试将算法从 Python 移植到 Go。它的中心部分是一棵使用字典构建的树,它应该保持这种状态,因为每个节点都可以有任意数量的子节点。所有的叶子都在同一层,所以最低层的字典包含其他字典,而最低层的字典包含 float 。像这样:
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]
执行类型断言,则会出现编译器错误或运行时错误。执行此操作的正确方法是什么?
最佳答案
对于这样的通用数据结构,Go 可能不是理想的解决方案。类型断言使之成为可能,但在其中操作数据需要您在 Python 和其他脚本语言中习惯的更多工作。
关于您的具体问题:您在 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 创建了一个新类型。这使得代码更容易理解。我还对树节点和树叶使用了相同的“map[string]interface{}”。如果你想从结果树中得到一个 float ,需要另一个类型断言:
leaf := t["a"].(Tree)["b"] // leaf is of type 'interface{}`.
val := leaf.(float32)
关于go - 理解 `interface{}` 在 Go 中的用法的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10899571/