Hi devs!
Today I'm going to show you how to implement polymorphism with slices on golang.
Imagine the situation where you want to implement a similar function on different structs. Interfaces are your best friend! For example, the classic function toString()
//our interface
type Element interface {
toString() string
}
//our first struct
type MyCustomStruct1 struct {
prop1 string
prop2 string
}
//our second struct
type MyCustomStruct2 struct {
awesomeProp string
}
//abstract implementation of our interface for MyCustomStruct1
func (m MyCustomStruct1) toString() string {
return m.prop1 + m.prop2
}
//abstract implementation of our interface for MyCustomStruct2
func (m MyCustomStruct2) toString() string {
return m.awesomeProp
}
At this point, nothing new of interfaces functionallity in golang. Well, now, we could think we can code something like that:
func printElementList(elements []Element) {
for _, e := range elements {
fmt.Println(e.toString())
}
}
//code inside main or another function
ms1 := []MyCustomStruct1{
MyCustomStruct1{prop1: "foo", prop2:"bar"},
MyCustomStruct1{prop1: "foo1", prop2:"bar1"},
}
printElementList(ms1)
That may work in other languages thinking on common functionality of hierarchy and polymorphism. However, the compiler will throw us that error:
cannot use ms1 (type []MyCustomStruct1) as type []Element in argument to printElementList
Ok, how can we aboard that problem? At the beggining I thought a map[int]Element
could solve the problem, but I don't want to have my slice ordered on a map where I'm not going to use integers.
Well, which is my solution? I surrounded the elements of slice with interfaces just like that:
var elements []interface{Element}
for _, m:= range ms1 {
elements = append(elements, m)
}
And, of course, I changed the declaration of function and the call:
func printElementList(elements []interface{Element}) {
for _, e := range elements {
fmt.Println(e.toString())
}
}
//code inside main or another function
printElementList(elements)
At this point, we can use printElementList
function with an slice of MyCustomStruct2 or another struct that implements Element interface:
ms2 := []MyCustomStruct2{
MyCustomStruct2{"foo"},
MyCustomStruct2{"bar"},
}
var elements2 []interface{Element}
for _, m:= range ms2 {
elements2 = append(elements2, m)
}
printElementList(elements2)
What do you think of that? Is an over complicated implementation?
Here you have the link to full code on play.golang:
Top comments (2)
Creative approach!
Another way is to type the slices as a list of Elements.
play.golang.org/p/qdbRJ1Kq_Kq
Wow, yes, I think I tried to use polymorphism on the wrong way. The problem I see with that implementation is the elements in the slice can be another type that implements the same interface.