Home > other >  How to implement two interfaces with same method name and different arguments
How to implement two interfaces with same method name and different arguments

Time:04-27

I have two different interfaces (from two different packages) that I want to implement. But they conflict, like this:

type InterfaceA interface {
  Init()
}

type InterfaceB interface {
  Init(name string)
}

type Implementer struct {} // Wants to implement A and B

func (i Implementer) Init() {}

func (i Implementer) Init(name string) {} // Compiler complains

It says "Method redeclared". How can one struct implement both interfaces?

CodePudding user response:

It is not possible.

In go you must have a single method signature.

You should rename one method.

CodePudding user response:

As already answered, this is not possible since Golang does not (and probably will not) support method overloading.

Look at Golang FAQ:

Experience with other languages told us that having a variety of methods with the same name but different signatures was occasionally useful but that it could also be confusing and fragile in practice. Matching only by name and requiring consistency in the types was a major simplifying decision in Go's type system.

CodePudding user response:

The method signatures must match. If you want dependency injection I would recommend the functional option pattern. Functional options are functions that return other functions that are called in a loop in the constructor. Here is an example of how to use functional options and the basics of interfaces in go.

package main

import (
    "fmt"
    "strconv"
)
type SomeData struct {
    data string
}
// SomeData and SomeOtherData both implement SomeInterface and SomeOtherInterface
// SomeInterface and SomeOtherInterface both implement each other.
type SomeInterface interface {
    String() string
    Set(data string)

}

func (s *SomeData)String() string {
    return s.data
}

func (s *SomeData)Set(data string)  {
    s.data = data
}

// SetDataOption is a functional option that can be used to inject a constructor dep
func SetDataOption(data string) func(*SomeData) {
   return func(s *SomeData) {
       s.Set(data)
   }
}
// NewSomeData is the constructor; it takes in 0 to many functional options and calls each one in a loop.
func NewSomeData(options ...func(s *SomeData)) SomeInterface {
   s := new(SomeData)

   for _, o := range options {
       o(s)
   }
   return s
}

//********************
type SomeOtherData struct {
    data string
    i    int
}

type SomeOtherInterface interface {
    String() string
    Set(data string)

}


func (s *SomeOtherData)String() string {
    return s.data   "  "   strconv.Itoa(s.i)
}

func (s *SomeOtherData)Set(data string)  {
    s.data = data
}


func SetOtherDataOption(data string) func(*SomeOtherData) {
   return func(s *SomeOtherData) {
      s.Set(data)
   }
}

func SetOtherIntOption(i int) func(*SomeOtherData) {
    return func(s *SomeOtherData) {
        s.i = i
    }
 }


// NewSomeOther data works just like NewSomeData only in this case, there are more options to choose from
// you can use none or any of them.
func NewSomeOtherData(options ...func(s *SomeOtherData)) SomeOtherInterface {
   s := new(SomeOtherData)

   for _, o := range options {
       o(s)
   }
   return s
}

//*********************************
// HandleData accepts an interface
// Regardless of which underlying struct is in the interface, this function will handle 
// either by calling the methods on the underlying struct.
func HandleData(si SomeInterface) {
    fmt.Println(si)  // fmt.Println calls the String() method of your struct if it has one using the Stringer interface
}

func main() {
    someData := NewSomeData(SetDataOption("Optional constructor dep"))
    someOtherData := NewSomeOtherData(SetOtherDataOption("Other optional constructor dep"), SetOtherIntOption(42))
    HandleData(someData) // calls SomeData.String()
    HandleData(someOtherData) // calls SomeOtherData.String()
    someOtherData = someData // assign the first interface to the second, this works because they both implement each other.
    HandleData(someOtherData) // calls SomeData.String()  because there is a SomeData in the someOtherData variable.
    
}
  • Related