Suppose that I have to implement two different interfaces declared in two different packages (in two different separated projects).
I have in the package A
package A
type interface Doer {
Do() string
}
func FuncA(Doer doer) {
// Do some logic here using doer.Do() result
// The Doer interface that doer should implement,
// is the A.Doer
}
And in package B
package B
type interface Doer {
Do() string
}
function FuncB(Doer doer) {
// some logic using doer.Do() result
// The Doer interface that doer should implement,
// is the B.Doer
}
In my main
package
package main
import (
"path/to/A"
"path/to/B"
)
type C int
// this method implement both A.Doer and B.Doer but
// the implementation of Do here is the one required by A !
func (c C) Do() string {
return "C now Imppement both A and B"
}
func main() {
c := C(0)
A.FuncA(c)
B.FuncB(c) // the logic implemented by C.Do method will causes a bug here !
}
How to deal with this situation ?
The implementation of interface's members will be given by the class who implements the interface implicitly or explicitly. C# allows the implementation of multiple interfaces with the same method name.
Method signature is used during the method creation. Two Methods cannot have same method signature. Methods can have same method name, and this process called method overloading.
Yes, a class can implement multiple interfaces. Each interface provides contract for some sort of behavior.
However, it can be achieved with interfaces, because the class can implement multiple interfaces. Note: To implement multiple interfaces, separate them with a comma (see example below).
As the FAQ mentions
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.
In your case, you would satisfy both interfaces.
You can you the can test whether an object (of an interface type) satisfies another interface type A.Doer
, by doing:
if _, ok := obj.(A.Doer); ok {
}
The OP adds:
But the logic implemented in the
Do
method to satisfyA
is completely different from the one inB
.
Then you need to implement a wrapper around you object:
DoerA
, which has your object C
as a field, and implement A.Do()
in a manner that satisfy how A.Do()
is supposed to workDoerB
, which has your same object C
as a field, and implement B.Do()
in a manner that satisfy how B.Do()
is supposed to workThat way, you will know which Doer to pass to a function expecting an A.Doer
or a B.Doer
.
You won't have to implement a Do()
method on your original object C
, which would be unable to cope with the different logic of A.Do()
and B.Do()
.
By definition, you are satisfying both:
A Go type satisfies an interface by implementing the methods of that interface, nothing more. This property allows interfaces to be defined and used without having to modify existing code. It enables a kind of structural typing that promotes separation of concerns and improves code re-use, and makes it easier to build on patterns that emerge as the code develops. The semantics of interfaces is one of the main reasons for Go's nimble, lightweight feel.
So, with that in mind, you can either:
a) Add comments to the the interface methods defining your expectations on the logic (see the io.Reader interface or a good example)
b) Add an extra method called ImplementsDoerA and ImplementsDoerB on the interfaces (also mentioned in the FAQ).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With