为了账号安全,请及时绑定邮箱和手机立即绑定

通过 Go 中的接口解耦......接口实现者的一部分?

通过 Go 中的接口解耦......接口实现者的一部分?

Go
弑天下 2021-09-09 15:06:17
好的。我知道这是一个常见问题解答,我认为答案是“放弃,那样不行”,但我只是想确保我没有遗漏任何东西。我仍然在思考使用接口的最佳实践和规则。我有不同包中的代码,我希望保持解耦,类似这样(不起作用,否则我不会在这里):package Atype 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 Btype 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不同的东西,因为...(喃喃内存分配,严格类型喃喃)。我的问题是:有没有一种正确的方法来做我最终想要的,那就是让 B.DoSomething() 接受一个 *A.Foo 而不必导入 A 并在 B.DoSomething() 中使用 *A.Foo函数签名(或更糟,在接口定义中)?我并没有试图欺骗编译器或陷入疯狂的运行时技巧。我知道我可能会更改 Foo.Bars() 的实现以返回 []Foolike,但这似乎很愚蠢和错误(为什么 A 必须了解 B 的任何信息?这打破了解耦的重点!)。不,那将不起作用,因为那样我就不能在 DoSomething() 中使用 Bars(),因为它没有在接口中定义。叹。如果我只是做错了™,我会接受并想出其他办法,但我希望我只是没有了解它应该如何工作的某些方面。
查看完整描述

1 回答

?
大话西游666

TA贡献1817条经验 获得超14个赞

正如错误消息所说,您不能将[]FooLike[]*Foo类型互换。

对于[]*Foo切片,后备数组在内存中看起来像这样:

| value1 | value2 | value3 | ... | valueN |

由于我们知道这些值将是 type *Foo,因此可以以直接的方式顺序存储它们。相反,[]FooLike切片中的每个元素可以是不同的类型(前提是它们符合FooLike)。所以后备数组看起来更像是:

| type1 | value1 | type2 | value2 | type3 | value3 | ... | typeN | valueN |

所以不可能在类型之间进行简单的转换:有必要创建一个新切片并复制值。

因此,您的基础类型需要返回接口类型的一部分才能使其正常工作。


查看完整回答
反对 回复 2021-09-09
  • 1 回答
  • 0 关注
  • 258 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信