Reputation: 738
I am getting deep into the Go architecture and I have problems with polymorphism. I simplified the problem and created new data for this example to be much more understandable my question.
I have this structure:
type Animal interface {
speak() string
}
type Cat struct {
Name string
}
type Dog struct {
Race string
}
And I want the structs to implement the interface, I proceed like that:
func (c Cat) speak() string {
return "Miaw!"
}
func (d Dog) speak() string {
return "Guau!"
}
func speak(a Animal) string {
return a.speak()
}
func speaks(a []Animal) string {
str := ""
for i := 0; i < len(a); i++ {
str += a[i].speak()
}
return str
}
So what I have created is:
The method speak
receives an Animal
and executes the method speak of the structure given (Animal
, which is Cat
or Dog
), and the method speaks
receive an slice of Animal
and executes the method speak of the structure given in every index of the slice (Animal
, which is Cat
or Dog
).
And for testing the methods, I implemented this function:
func test() {
cat1 := Cat{
Name: "Cat1",
}
cat2 := Cat{
Name: "Cat2",
}
cat3 := Cat{
Name: "Cat3",
}
arrayCats := []Cat{cat1, cat2, cat3}
speak(cat1)
speak(cat3)
speak(cat2)
speaks(arrayCats) //This line gives an error to the Compiler
}
I upload the error that the compiler gives to me:
Can someone please explain to me why I can play with polimorfish in a functions that receives only one element and why not in the function that receives an slice of that element?
I really need to find the solution to this problem to implement it in different parts of my application, and I have no idea how to solve the problem nor how to implement a practical and scalable solution (the slice in the real application will contain a hight number of elements).
I found this answers related useful to understand more my problem, but still I don't get what is the problem or the solution: Answer1 Answer2Answer3
Upvotes: 0
Views: 1867
Reputation: 11626
A fixed version, on Play
As others have mentioned, there is no automatic type coercion in Go. And []Cat is totally different than []Animal.
All you really needed to do was create a slice of the type you will pass to the speaks
method.
So, change:
arrayCats := []Cat{cat1, cat2, cat3}
to
arrayCats := []Animal{cat1, cat2, cat3}
And it works fine.
If you are used to languages like Java, they go about this in a really different way in that java treats all things as an Object
. So, when they added generics it was a simple compile time trick where the collection was really just a list of Object
and the compiler inserts a cast at the extraction point.
Things like int
are not objects in java which is why you can't create a List<int>
, because then the List<Object>
casting trick wouldn't work. Because int
isn't a subclass of Object
.
In go, there's no common base type for things like struct, so there's no real way to do the cast trick that java does.
As others have mentioned, there are also some specific features on how go manages memory that makes things like auto-conversion not work in a generic way (ie: a slice of int64 is a different memory footprint than a slice of int32, so not castable without allocation).
the go team has stated they are looking in to adding generics in some form, which would potentially make things like this easier to write. But that will come with a cost of invisible runtime or compile time complexity (or both).
Today, since it is not automatic, you have to write the code to do the conversion. Which has the downside of you write more code. And the upside of it being obvious what's happening in the system.
Upvotes: 2
Reputation: 154
Go can’t type cast arrays. You need to create new array of target type manually, then use for loop to type cast each element of source array and put result to target array.
Reason: go doesn’t hide from you memory allocations, this is reason why you need to create new and feel it manually.
https://golang.org/doc/faq#convert_slice_of_interface
Upvotes: 2