I have two different types of structs in my app.
I'll show it as a simplified example:
type typeA struct {
fieldA1 int
fieldA2 string
}
type typeB struct {
fieldB1 float32
fieldB2 bool
}
First I init slices of them, then I want to store them in DB.
a := []typeA{
{10, "foo"},
{20, "boo"},
}
b := []typeB{
{2.5, true},
{3.5, false},
}
My first attempt was to iterate over first slice, then over second slice. It works just fine, but doesn't look DRY. The code is clearly duplicated:
printBothArrays(a, b)
// ...
func printBothArrays(dataA []typeA, dataB []typeB) {
// Not DRY
for i, row := range dataA {
fmt.Printf("printBothArrays A row %d: %v
", i, row)
}
for i, row := range dataB {
fmt.Printf("printBothArrays B row %d: %v
", i, row)
}
}
A wrong way to make it DRY is to split it into 2 functions:
printArrayA(a)
printArrayB(b)
// ...
func printArrayA(data []typeA) {
// Not DRY too, because the code is just split between 2 funcs
for i, row := range data {
fmt.Printf("printArrayA row %d: %v
", i, row)
}
}
func printArrayB(data []typeB) {
// Not DRY too, because the code is just split between 2 funcs
for i, row := range data {
fmt.Printf("printArrayB row %d: %v
", i, row)
}
}
These two functions' signatures are different, but the code is just the same!
I thought of an universal function which can take any []struct and just store it. As my store function can take any interface{}, I thought of this:
func printArrayAny(data [](interface{})) {
for i, row := range data {
fmt.Printf("printArrayAny row %d: %v
", i, row)
}
}
But I've tried different ways and I can't match any shared interface. I'm getting errors like:
cannot use a (type []typeA) as type []interface {} in argument to printArrayAny
I don't really want to make any heavy lifting like converting it to []map[string]interface
, or using reflect
, as both slices are really big.
Is there a way to modify printArrayAny
so it can receive and iterate over any arbitrary []struct
?
Go playground link: https://play.golang.org/p/qHzcQNUtLIX