My recent involvement with my new side project, go-linq, showed me that type system of Go is not designed for anything near object-oriented programming. There are no generics, no type inheritance, or anything helpful for certain purposes.
However there is a type called interface{}
you can assign pretty much anything into it, like object
in .NET or Object
in Java:
var o interface{}
o := 3.14
o := Student{Name:"Ahmet"}
and it does not give any compilation errors. So let’s say you need a function that accepts slices of any type. If you are thinking to do something like:
func Method(in []interface{}){...}
...
slice := []int{1,2,3}
Method(slice) // gives error
That gives a compilation error, because []int
is not an []interface{}
. So what’s the solution here? You can require users of Method
to convert their slices to []interface{}
. Now they have to convert their []AnyType
to []interface{}
with the help of a function like:
func conv(in []AnyType) (out []interface{}) {
out = make([]interface{}, len(in))
for i, v := range in {
out[i] = v
}
return
}
But that does not scale. If your user of Method
(and this can be a common function like Map
, Filter
etc.) has N different types they would like to pass to Method
, they have to write N conv
methods.
What can we do here? Of course, reflection. We will take input as interface{}
(which can be of any value) and we will convert it to a slice internally and use it in our Method
. How to do that:
func takeSliceArg(arg interface{}) (out []interface{}, ok bool) {
slice, success := takeArg(arg, reflect.Slice)
if !success {
ok = false
return
}
c := slice.Len()
out = make([]interface{}, c)
for i := 0; i < c; i++ {
out[i] = slice.Index(i).Interface()
}
return out, true
}
func takeArg(arg interface{}, kind reflect.Kind) (val reflect.Value, ok bool) {
val = reflect.ValueOf(arg)
if val.Kind() == kind {
ok = true
}
return
}
takeArg()
function tries to convert value to the specified reflect.Kind
and takeSliceArg()
function tries to convert a value passed to itself to a slice of interface{}
. Although, there’s just a little bit of performance drawback caused by reflection, it is not much.
That’s it. This approach is inspired by Tobia Confronto’s fn project and integrated to go-linq.
This post is written while drunk I don’t take any responsibility about it.
Leave your thoughts