行。我知道这是一个常见问题解答,我认为答案是“放弃,它不会那样工作”,但我只是想确保我没有错过任何东西。
我仍然围绕着使用接口的最佳实践和规则。我有不同包中的代码,我宁愿保持解耦,这样的事情(不起作用,或者我不会在这里):
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中使用* A.Foo( )的函数签名(或者更糟糕的是,在接口定义中)?我并没有试图欺骗编译器或进入疯狂的运行时技巧。我明白我可能会改变Foo.Bars()的实现来返回[] Foolike,但这似乎是愚蠢和错误的(为什么A必须知道关于B的任何事情?这打破了解耦事情的全部意义!)。< / p>
我想另一个选择是删除Bars()作为实现接口的要求,并依赖其他方法来强制执行要求。但是感觉不太理想(如果Bars()是唯一导出的方法呢?)。编辑:不,那不行,因为那时我不能在DoSomething()中使用Bars(),因为它没有在界面中定义。叹息。
如果我只是做错了,我会接受并想出其他的东西,但我希望我没有得到它应该如何工作的某些方面。
答案 0 :(得分:1)
正如错误消息所示,您无法互换地处理[]FooLike
和[]*Foo
类型。
对于a []*Foo
切片,支持数组在内存中看起来像这样:
| value1 | value2 | value3 | ... | valueN |
由于我们知道值将是*Foo
类型,因此它们可以以直接的方式顺序存储。相反,[]FooLike
切片中的每个元素可以是不同的类型(前提是它们符合FooLike
)。因此支持数组看起来更像:
| type1 | value1 | type2 | value2 | type3 | value3 | ... | typeN | valueN |
因此,在类型之间进行简单的转换是不可能的:有必要创建一个新的切片并复制这些值。
因此,您的基础类型需要返回一个接口类型的片段才能生效。