Recently I started to learn the Go language.
I am trying to understand interface principles in Go and was completely puzzled by one thing.
The duck principle says: if something quacks like a duck and walks like a duck, then it's a duck.
But I wondered how Go will behave if we have three interfaces like this:
// Interface A
type InterfaceA interface {
ActionA() string
}
// Interface B
type InterfaceB interface {
ActionB() string
}
And interface C
, which does something different but has functions which are similar to interfaces A
and B
functions:
// Interface C with methods A and B interfaces
type InterfaceC interface {
ActionA() string
ActionB() string
}
Then we have three structures which implement the interfaces above:
type StructA struct{}
// If it does ActionA then it's interface A
func (a StructA) ActionA() string {
return "Interface A implementation"
}
type StructB struct{}
// If it does ActionB then it's interface B
func (b StructB) ActionB() string {
return "Interface B implementation"
}
type StructC struct{}
// If it does ActionA and ActionB, it's an Interface C
func (c StructC) ActionA() string {
return "Interface C implementation"
}
func (c StructC) ActionB() string {
return "Interface C implementation"
}
And a function that identifies which type it gets:
func getType(data interface{}) string {
switch data.(type) {
default:
return "Unknown"
case InterfaceA:
return "Interface A"
case InterfaceB:
return "Interface B"
case InterfaceC:
return "Interface C"
}
}
Code inside main
function:
func main() {
a := StructA{}
fmt.Println(a.ActionA())
fmt.Println(getType(a)) // should return InterfaceA
fmt.Println("")
b := StructB{}
fmt.Println(b.ActionB())
fmt.Println(getType(b)) // should return InterfaceB
fmt.Println("")
c := StructC{}
fmt.Println(c.ActionA())
fmt.Println(c.ActionB())
fmt.Println(getType(c)) // should return InterfaceC
}
Output:
Interface A implementation
Interface A
Interface B implementation
Interface B
Interface C implementation
Interface C implementation
Interface A
After some experiments I found out if we change the case
order inside switch
then the function identifies the type correctly:
func getType(data interface{}) string {
switch data.(type) {
default:
return "Unknown"
case InterfaceC:
return "Interface C"
case InterfaceB:
return "Interface B"
case InterfaceA:
return "Interface A"
}
}
Output:
Interface A implementation
Interface A
Interface B implementation
Interface B
Interface C implementation
Interface C implementation
Interface C
See also full code on play.golang.org
My question: Is it a bug or a feature? And if it's a feature, how should I change getType
so that the function doesn't depend on case
order?