两个不同类型如何在golang中使用接口实现相同的方法?

时间:2015-07-19 20:24:12

标签: go

说我有两个结构:

type First struct {
    str string
}
type Second struct {
    str string
}

我希望他们两个都实现接口A:

type A interface {
    PrintStr() //print First.str or Second.str
}

对于第一个和第二个结构都有这样的实现似乎是多余的:

func (f First) PrintStr() {
    fmt.Print(f.str)
}

func (s Second) PrintStr() {
    fmt.Print(s.str)
}

有没有办法可以为实现接口A的所有结构实现一个实现?像这样的东西,但它似乎不起作用:

func (a A) PrintStr() {
    fmt.Print(a.str)
}

谢谢!

4 个答案:

答案 0 :(得分:14)

不,你不能,但是你可以创建一个基本类型,然后将它嵌入到你的2结构中,因此只需要基类型的实现:

type WithString struct {
    str string
}

type First struct {
    WithString
}

type Second struct {
    WithString
}

type A interface {
    PrintStr() //print First.str or Second.str
}

func (w WithString) PrintStr() {
    fmt.Print(w.str)
}

用法:

a := First{
    WithString: WithString{
        str: "foo",
    },
}

Complete Example on Playground

Embed documentation

答案 1 :(得分:3)

如果打印逻辑依赖于界面而不依赖于结构本身,那么最好将打印移动到通过界面操作的自由函数。

在您的情况下,PrintStr方法用于打印作为每个结构成员的字符串 在这种情况下,这意味着每个结构应该实现一个返回用于打印的必要字符串的接口,PrintStr成为一个带有Printable参数的函数。

type First struct {
    str string
}
type Second struct {
    str string
}

type Printable interface {
     String() string
}

func (p First) String() string {
    return p.str
}

func (p Second) String() string {
    return p.str
}

func PrintStr(p Printable) {
    fmt.Print(p.String())
}

您对A界面的使用是非惯用的,因为界面不应依赖于其功能的实施

相反,使用此解决方案,您仍然可以保留A接口,但会简化每个实现:

func (f First) PrintStr() {
    PrintStr(f)
}

func (s Second) PrintStr() {
    PrintStr(s)
}

它仍然是多余的,但逻辑在于从那里调用的函数,限制了在修改打印逻辑的情况下进行复制粘贴的需要。

这种模式在Go标准库中很常见,因为许多有用的函数是基于它们无法扩展的接口构建的,例如io.Reader
它是一个只有一种方法的简单界面,但它可以从许多其他包中使用 如果你看一下ioutil.ReadAll函数,可以认为它可以作为io.Reader接口的另一种方法实现,但是这使读者更简单,专注于他们的单一方法,同时允许任何实现者免费使用ReadAll。

答案 2 :(得分:2)

为什么不只是将该函数放在接口之外,而将类型A作为参数传递呢?

type A interface {}

type First struct {
    str string
}
type Second struct {
    str string
}

func PrintStr(a A) {
    fmt.Print(a.str)
}

答案 3 :(得分:1)

也许不是解决问题的最佳方法,但你可以使用包装器来避免两次“实现”这个功能,如下所示:

type First struct {
    str StringWrapper
}
type Second struct {
    str StringWrapper
}


type StringWrapper struct {
    str string
}
func (f StringWrapper) PrintStr() {
    fmt.Print(f.str)
}

func main() {
    var a First = First{str:StringWrapper{str: "aaa"}};
    a.str.PrintStr();
}