我仍在思考 Go 中的接口(interface),但我正在编写一个包,它将获取结构图并将它们作为树打印到标准输出。为此,我定义了一个 interface
调用TreeNode
其中包含一个方法 GetChildren
它需要返回一个结构 slice 实现 TreeNode
.这样我就可以从根开始向下递归树。即这是完整的接口(interface)定义:
type TreeNode interface {
GetName() string
GetChildren() []TreeNode
}
我听说这是“接受接口(interface)并返回结构”的最佳实践。这很有意义。但是,当我尝试在
struct
上实现这些方法时,我开始遇到问题。 .这是一个完整的例子:package main
import "fmt"
type MyStruct struct {
Name string
Children []*MyStruct
}
type TreeNode interface {
GetName() string
GetChildren() []TreeNode
}
func PrintTree(root TreeNode) {
// Print the nodes recursively
fmt.Println(root.GetName())
// etc.
}
func main() {
child1 := &MyStruct{
Name: "Child 1",
}
child2 := &MyStruct{
Name: "Child 2",
}
root := &MyStruct{
Name: "Root",
Children: []*MyStruct{child1, child2},
}
PrintTree(root)
}
func (my_struct *MyStruct) GetName() string {
return my_struct.Name
}
func (my_struct *MyStruct) GetChildren() []*MyStruct {
return my_struct.Children
}
在调用
PrintTree
在 main
编译器提示说cannot use root (type *MyStruct) as type TreeNode in argument to PrintTree:
*MyStruct does not implement TreeNode (wrong type for GetChildren method)
have GetChildren() []*MyStruct
want GetChildren() []TreeNode
这有点令人惊讶,因为界面显示
GetChildren()
应该返回实现 TreeNode
的对象和 *MyStruct
确实实现了TreeNode
.但很明显,关于编译器如何处理这种情况(递归需要接口(interface)类型),我缺少一些东西。如果我接受编译器的建议(以及 this similar question 的建议)并更改
MyStruct
的 GetChildren
的实现返回 []TreeNode
我在 GetChildren()
中收到一个新的编译器错误执行说cannot use my_struct.Children (type []*MyStruct) as type []TreeNode in return argument
这也是一个惊喜。另外,共识似乎是我应该返回
struct
s 来自方法而不是返回 interface
s。我绝对可以接受返回 []TreeNode
从那个方法,但我一定忽略了一些东西,因为编译器不高兴。转到版本:
go version go1.13.8 darwin/amd64
最佳答案
“接受接口(interface),返回结构”不是规则,而是一种让生活更轻松的做法。但是,在这种情况下,对于您的接口(interface)定义,您没有太多选择。
您可以保留您的设计,但实现 GetChildren:
func (my_struct *MyStruct) GetChildren() []TreeNode {
ret:=make([]TreeNode,0,len(my_struct.Children))
for _,x:=range my_struct.Children {
ret=append(ret,x)
}
return ret
}
这是必需的,因为 Go 的类型系统具有严格的性质。
或者,您可以稍微修改您的设计:
type MyStruct struct {
Name string
Children []TreeNode
}
如果您在使用
Children
时需要访问底层结构,这将要求您使用类型断言。 .但是,它可以让您构建具有不同类型节点的树。
关于go - 如何使用其中一种方法返回同一接口(interface)的对象的接口(interface)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61466254/