Go接口方法返回接口与返回混凝土类型的方法不匹配

时间:2015-12-09 22:24:03

标签: go types interface

我正在努力让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个派对套餐我不想修改。

我希望能够编写自己的结构以实现所述接口,因此也不能选择与具体返回类型的接口。

我必须假设有办法做到这一点。

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上。根据您的问题,两者都有用。您可以使用此技术来帮助其他包类型符合您的任何需要。

这并不意味着BarMyBar可以互换,但它们非常接近,并且您可以根据需要在它们之间进行转换。< / p>

答案 1 :(得分:2)

  

我希望能够编写自己的结构来实现所述接口,因此也不能选择与具体返回类型的接口。

“我想要”和Go不匹配。

  

我必须假设有办法做到这一点。

不,没有。接口完全匹配。 Go没有超类型或专业化的概念。

答案 2 :(得分:1)

正如其他人所说,Go并不支持你要做的事情。

您是否认为您的设计可能过于复杂?

您不会像在Java等其他语言中那样在Go中找到工厂模式的工厂。(例如)。

至少,这是我假设您正在通过返回返回接口的接口的接口来做的事情。

您始终可以创建一个新包来保存工厂工厂接口。

但通常情况下,我首先会尝试查看该抽象级别是否值得您在代码库中获取的可读性。可能有一种更简单的方法来解决您的问题。