我正在努力让Go接口工作,我遇到的问题是Go 接口方法返回go 接口只有在实现声明时才有效接口,而不是实现接口的具体类型。
在以下示例中,我收到:
prog.go:29:不能使用& f(键入* Bar)作为StringerGetter类型 打印机的参数:* Bar没有实现StringerGetter(错误 GetStringer方法的类型)有GetStringer()* Foo想要的 GetStringer()fmt.Stringer
package main
import "fmt"
type Foo struct {
val string
}
func (f *Foo) String() string {
return f.val
}
type StringerGetter interface {
GetStringer() fmt.Stringer
}
type Bar struct{}
func (b *Bar) GetStringer() *Foo {
return &Foo{"foo"}
}
func Printer(s StringerGetter) {
fmt.Println(s.GetStringer())
}
func main() {
f := Bar{}
Printer(&f)
}
但是,如果我将func (b *Bar) GetStringer() *Foo {
更改为func (b *Bar) GetStringer() fmt.Stringer {
,则按预期工作。
Foo
确实符合fmt.Stringer
上面是说明问题的简单示例代码。
对于我尝试编写的代码,我创建的接口位于我的"main"
包中,而我正在编写接口的具体类型位于第3个派对套餐我不想修改。
我希望能够编写自己的结构以实现所述接口,因此也不能选择与具体返回类型的接口。
我必须假设有办法做到这一点。
答案 0 :(得分:3)
您的问题是,您试图让其他人(即其他包裹)类型符合其实际上并不符合的界面。你不能这样做。但是你可以使你的类型符合你想要的任何东西。你可以让你的类型包装他们的类型。有两种方法可以做到这一点。 Here's one:
type MyBar Bar
func (b *MyBar) GetStringer() fmt.Stringer {
return &Foo{"foo"}
}
func main() {
f := MyBar(Bar{})
Printer(&f)
}
现在我们已经创建了一个包含MyBar
的新类型Bar
并提供了您想要的界面。这种方法不会继承"但是,来自Bar
的任何其他功能。你必须包装你想要的每一件事,你可能需要重新实现(因为你无法访问底层的impl)。
但你也可以嵌入Bar
,并且"继承"你所做的一切都没有改变并且可以访问底层的impl(这可能更接近你想要的)。 For example:
type MyBar struct{ Bar }
func (b *MyBar) GetStringer() fmt.Stringer {
return b.Bar.GetStringer()
}
func main() {
f := MyBar{Bar{}}
Printer(&f)
}
现在,如果Bar
有其他方法,那么它们将免费显示在MyBar
上。根据您的问题,两者都有用。您可以使用此技术来帮助其他包类型符合您的任何需要。
这并不意味着Bar
和MyBar
可以互换,但它们非常接近,并且您可以根据需要在它们之间进行转换。< / p>
答案 1 :(得分:2)
我希望能够编写自己的结构来实现所述接口,因此也不能选择与具体返回类型的接口。
“我想要”和Go不匹配。
我必须假设有办法做到这一点。
不,没有。接口完全匹配。 Go没有超类型或专业化的概念。
答案 2 :(得分:1)
正如其他人所说,Go并不支持你要做的事情。
您是否认为您的设计可能过于复杂?
您不会像在Java等其他语言中那样在Go中找到工厂模式的工厂。(例如)。
至少,这是我假设您正在通过返回返回接口的接口的接口来做的事情。
您始终可以创建一个新包来保存工厂工厂接口。
但通常情况下,我首先会尝试查看该抽象级别是否值得您在代码库中获取的可读性。可能有一种更简单的方法来解决您的问题。