Reputation: 14161
I'm having difficulty getting my head around the usage of interface{}
types with Go.
In this instance I have a function which inserts a value into the middle of a slice somewhere. It looks like this:
type mystruct {
a, b, c int
}
func insert(ar []mystruct, val mystruct, i int) []mystruct {
l := len(ar)
if l == cap(ar) {
tmp := make([]mystruct, l + 1, (l * 2) + 1)
copy(tmp, ar[0:i])
copy(tmp[i+1:], ar[i:])
ar = tmp
} else {
ar = ar[0:l+1]
copy(ar[i+1:], ar[i:])
}
ar[i] = val
return ar
}
I'd like for that function to be able to accept interface{}
for both ar
and val
so that I could pass it a slice and value of any type and it would perform the insert without complaint.
From what I have read so far I believe this should be done with the reflect
package. I have read the Rules of Reflection and various tutorials on reflection and interface{}
, but I'm not sure how to approach this. I'd like to minimize overhead as much as possible, I understand reflection is going to slow the code down a bit but what is the most efficient way of doing this?
Thanks!
Upvotes: 3
Views: 2630
Reputation: 24898
The whole "grow if at capactiy" code is unnecessary; use the built-in append
– it does exactly that for you.
Change the signature to:
func insert(ar interface{}, val interface{}, i int) interface{}
Then check that ar
is a slice and that the element type of ar
is the same type as val
:
at, vt := reflect.TypeOf(ar), reflect.Typeof(val)
if at.Kind() != reflect.Slice {
panic(fmt.Sprintf("expected slice, got %T", at))
}
if at.Elem() != vt {
panic("first argument must be a slice of the second argument's type")
}
After type validation, get a hold of some reflect.Value
s:
av, vv := reflect.ValueOf(ar), reflect.ValueOf(val)
And get moving stuff around using e.g:
(reflect.Value).Index(int)
to access element of the slice.reflect.Copy
to copy to and from slices à la built-in copy
reflect.Append
to append to a slice Value
(reflect.Value).Set(reflect.Value)
to set the value of a settable element (something you got out of a slice, for instance).reflect.Append
or reflect.AppendSlice
to append to a slice à la built-in append
.Once you have your final reflect.Value
representing the result slice; return it as an interface{}
like this:
return result.Interface()
Upvotes: 1