【发布时间】:2015-01-30 23:49:11
【问题描述】:
好的。我知道这是一个常见问题解答,我认为答案是“放弃,那样不行”,但我只是想确保我没有遗漏什么。
我仍在思考使用接口的最佳实践和规则。我有不同包中的代码,我希望保持解耦,类似这样(不起作用,或者我不会在这里):
package A
type Foo struct {}
func (f *Foo) Bars() ([]*Foo, error) {
foos := make([]*Foo, 0)
// some loop which appends a bunch of related *Foo to foos
return foos, nil
}
package B
type Foolike interface {
Bars() []Foolike
}
func DoSomething(f Foolike) error {
// blah
}
这样,编译器会抱怨:
cannot use f (type *A.Foo) as type Foolike in argument to B.DoSomething:
*A.Foo does not implement Foolike (wrong type for Bars method)
have Bars() ([]*A.Foo, error)
want Bars() ([]Foolike, error)
现在,我认为 []Foolike 本身并不是一个接口签名;它是一片 Foolike 接口的签名。我想我也觉得编译器将 []*A.Foo 和 []Foolike 视为不同的东西,因为 ...(mumble 内存分配,严格键入 mumble)。
我的问题是:有没有正确的方法来做我最终想要的,即让 B.DoSomething() 接受 *A.Foo 而不必导入 A 并在 B.DoSomething( ) 的函数签名(或者更糟糕的是,在接口定义中)?我并没有试图欺骗编译器或陷入疯狂的运行时技巧。我知道我可能会更改 Foo.Bars() 的实现以返回 []Foolike,但这似乎是愚蠢和错误的(为什么 A 必须知道 B 的任何事情?这打破了解耦的全部意义!)。
我想另一种选择是删除 Bars() 作为实现接口的要求,并依靠其他方法来执行要求。不过,这感觉不太理想(如果 Bars() 是唯一的导出方法怎么办?)。 编辑:不,那行不通,因为那时我不能在 DoSomething() 中使用 Bars(),因为它没有在接口中定义。叹息。
如果我只是做错了™,我会接受这一点并想出其他办法,但我希望我只是没有了解它应该如何工作的某些方面。
【问题讨论】:
-
解耦是一回事。但是当你递归定义你的接口时,它只能做到这一点。然后包
A必须导入包B。 -
我建议将其发布到邮件列表 (groups.google.com/forum/#!forum/golang-nuts)。我认为开发人员经常去那里。然后你可以在这里发布他们的答案。
-
seong 的返回使
f.Bars实际上返回[]Foolike的答案是我看到的最好的问题描述——如果你能描述用例(比如,@987654329 @ 和Bars真的是,等等)也许有一个聪明的方法可以解决它,包括返回除了切片或其他东西之外的东西。但可能没有。 -
感觉您使用的界面不正确。必须从界面中“导出”一些信息,例如“我们是界面的数组”,这似乎很奇怪。缺了点什么。你能告诉我们你想做什么吗?
-
另请注意,包不一定与“解耦”相关。包通常代表一个非常一般意义上的“想法”。根据您的问题,您的包
A和B应该在一个包中。循环导入或类似的依赖问题通常暗示你应该重新考虑你的包结构。
标签: interface go decoupling