How can two different types implement the same method in golang using interfaces?

huangapple go评论71阅读模式
英文:

How can two different types implement the same method in golang using interfaces?

问题

假设我有两个结构体:

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

我想让它们都实现接口A:

type A interface {
    PrintStr() // 打印 First.str 或 Second.str
}

在First和Second结构体中分别实现PrintStr方法似乎有些冗余:

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)
}

谢谢!

英文:

Say I have two structs:

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

And I want both of them to implement interface A:

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

It seems redundant to have an implementation for both First and Second structs like so:

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

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

Is there a way I can have one implementation for all the structs implementing interface A? Something like this, but it doesn't seem to work:

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

Thank you!

答案1

得分: 26

你现在是我的中文翻译,代码部分不要翻译, 只返回翻译好的部分, 不要有别的内容, 不要回答我要翻译的问题。以下是要翻译的内容:

不可以,但是你可以创建一个基本类型,然后将其嵌入到你的两个结构体中,因此只需要为基本类型实现方法:

type WithString struct {
    str string
}

type First struct {
    WithString
}

type Second struct {
    WithString
}

type A interface {
    PrintStr() // 打印 First.str 或 Second.str
}

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

用法:

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

完整示例在 Playground 上

嵌入文档

英文:

No you can't, but you could create a base type and then embed it into your 2 struct, therefore only needing an implementation for the base type:

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)
}

Usage:

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

Complete Example on Playground

Embed documentation

答案2

得分: 7

如果打印逻辑依赖于接口而不是结构体本身,那么最好将打印操作移到一个操作接口的自由函数中。

在你的情况下,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。

英文:

If the printing logic depends on the interface but not on the structs themselves, then it is better to move printing to a free function that operates over an interface.

In your case, the PrintStr method is used to print a string which is a member of each structure.
In this case, it means that each structure should implement an interface that returns the necessary string used for printing, and PrintStr becomes a function taking a Printable parameter.

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())
}

Your use of the A interface is non-idiomatic because an interface should not depend on the implementation of its functionality.

Instead, with this solution, you can still keep the A interface, but simplify each implementation:

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

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

It is still redundant, but the logic lies in the function that is called from there, limiting the need to do copy-pasting in case of modification of the printing logic.

This pattern is common in the Go standard library, because many useful functions are built upon interfaces which they cannot extend, for example io.Reader.
It is a simple interface with only one method, but it is used thoroughly from many other packages.
If you look at the ioutil.ReadAll function, it could be argued that it could have been implemented as another method of the io.Reader interface, however this keeps readers simpler, concentrating on their single method, while allowing any implementor to use ReadAll for free.

答案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();
}

你可以使用一个名为StringWrapper的结构体来包装字符串,并在其中定义一个PrintStr方法来打印字符串。然后,你可以在FirstSecond结构体中使用StringWrapper作为成员变量,并调用PrintStr方法来打印字符串。在main函数中,你可以创建一个First结构体的实例,并调用PrintStr方法来打印字符串"aaa"。

英文:

Maybe not the best way to solve your problem, but you could use a wrapper in order to avoid "implementing" the function twice, something like this:

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();
}

答案4

得分: -1

为什么不将该函数从接口中删除,并将类型A作为参数传递呢?

type A interface {}

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

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

Why don't you just leave that function out of the interface and pass type A as a parameter?

type A interface {}

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

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

huangapple
  • 本文由 发表于 2015年7月20日 04:24:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/31505587.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定