Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

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!

like image 990
Ekaterina Avatar asked Jul 19 '15 20:07

Ekaterina


People also ask

Can a type fulfill multiple interfaces?

A type can implement multiple interfaces.

Can an interface implement another interface Golang?

In embedding, an interface can embed other interfaces or an interface can embed other interface's method signatures in it, the result of both is the same as shown in Example 1 and 2. You are allowed to embed any number of interfaces in a single interface.

Can a struct implement multiple interfaces?

A class or struct can implement multiple interfaces, but a class can only inherit from a single class.

How interfaces are implemented in Golang?

Go Interfaces are implemented implicitly Unlike other languages like Java, you don't need to explicitly specify that a type implements an interface using something like an implements keyword. You just implement all the methods declared in the interface and you're done.


2 Answers

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

like image 164
TheHippo Avatar answered Oct 18 '22 17:10

TheHippo


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.

like image 39
SirDarius Avatar answered Oct 18 '22 19:10

SirDarius