繁体   English   中英

通过Go中的接口解耦…接口实现器的一部分?

[英]Decoupling via Interfaces in Go… Slice of interface implementors?

好。 我知道这是一个常见问题解答,我认为答案是“放弃,那样行不通”,但我只是想确保自己没有遗漏任何东西。

我仍在围绕使用接口的最佳实践和规则进行研究。 我在不同的程序包中有一些代码,希望保持解耦,例如(不起作用,或者我不在这里):

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不同的东西,因为...( 喃喃内存分配,严格类型喃喃 )。

我的问题是:有没有一种正确的方法来做我最终想要的事情,那就是让B.DoSomething()接受* A.Foo而不必导入A并在B.DoSomething()的中使用* A.Foo函数签名(或更糟糕的是,在接口定义中)? 我并不想尝试欺骗编译器或陷入疯狂的运行时技巧。 我知道我可能可以将Foo.Bars()的实现更改为返回[] Foolike,但这似乎是愚蠢和错误的(为什么A必须对B有所了解?这打破了将事物解耦的整个观点!)。

我猜另一个选择是删除Bars()作为实现接口的要求,并依靠其他方法来强制执行该要求。 但是,这感觉并不理想(如果Bars()是唯一的导出方法呢?)。 编辑:不,那是行不通的,因为那样我就不能在DoSomething()中使用Bars()了,因为它没有在接口中定义。 叹。

如果我只是做错了,那我会接受并想出其他办法,但是我希望我只是不了解它应该如何工作。

如错误消息所述,您不能互换处理[]FooLike[]*Foo类型。

对于[]*Foo切片,支持数组在内存中将如下所示:

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

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

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

因此,不可能在类型之间进行简单的转换:有必要创建一个新的slice并复制这些值。

因此,您的基础类型将需要返回接口类型的一部分才能起作用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM