I have 15 custom types in this application, and the processing I wish to do to them is actually very generic to them all.
In each case, I need to iterate over a slice of whatever type it is that I am working with.
an interface is what currently gets passed, but it certainly doesn't have to remain that way
I have the following code :
func ProcessSlice(in interface{}){
switch reflect.TypeOf(p.in).Kind() {
case reflect.Slice:
s := reflect.ValueOf(p.in)
for i := 0; i < s.Len(); i++ {
fmt.Println(reflect.ValueOf(p.in))
}
}
}
the fmt.Println is there for debugging, and I get the following sort of output :
[map[_Id:4K7qx_mUSbV-----------== name:<name ommited> _class:basic_organization] map[_Id:4K7qx_mUnvB-----------== name:<name omitted> _class:basic_organization]]
My real question here, is let's say I have the types :
MyCustomStructA,
MyCustomeStructB
and I bail into that function with a slice of either, how can I end up in that loop, working with actual struct items? Because at the minute, I wind up with a map, and that is not what I want here.
I'd suggest making all of those custom types implement an interface which says that they're 'processable'. Then in ProcessSlice()
, you can iterate over the slice elements and process those that implement the Processable
interface. Something like this:
// Processable is a type that can be 'processed'
type Processable interface {
Process()
}
// ProcessSlice processes a slice of types that can be processed
func ProcessSlice(in interface{}) {
switch reflect.TypeOf(in).Kind() {
case reflect.Slice:
s := reflect.ValueOf(in)
for i := 0; i < s.Len(); i++ {
v := s.Index(i).Interface()
if p, ok := v.(Processable); ok {
p.Process()
}
}
}
}
This way, all of the processing logic for a type can be attached to the type itself and you also wouldn't need to modify ProcessSlice()
when adding new custom types.
Coming to the actual question, you can use a type switch on the slice value like this (though I prefer the interface way more)
// ProcessSliceConcreteTypes processes a slice of types based on the type of the slice
func ProcessSliceConcreteTypes(in interface{}) {
switch reflect.TypeOf(in).Kind() {
case reflect.Slice:
s := reflect.ValueOf(in)
switch sv := s.Interface().(type) {
case []S1:
for _, s1 := range sv {
s1.Process()
}
case []S2:
for _, s2 := range sv {
s2.Process()
}
default:
// error here
}
}
}
(See it on the Go Playground)