I want to create a function that takes either a map or an array of whatever and iterates over it calling a function on each item which knows what to do with whatever types i
For your example to work, you would need to build an array of interface{}
(or a map), in order for the right type to be detected:
// This won't work, as the .(type) would be []S
someS := []S{S{}}
DoTheThingToAllTheThings(someS)
// This will: it will go in case []interface{}:
someSI := make([]interface{}, len(someS))
for i, s := range someS {
someSI[i] = s
}
DoTheThingToAllTheThings(someSI)
See a full example here.
But that means you would still work with interface{}
in your DoTheThing
function.
There is no real generic here, as I mentioned in "What would generics in Go be?".
The function fmt.Printf("%v\n", data_interface)
does exactly what you want. It will print the whole map or array passed to it.
You can find the implementation here: http://golang.org/src/pkg/fmt/print.go?h=printArg#L708
The line near the end of printArg
is key:
return p.printReflectValue(reflect.ValueOf(arg), verb, plus, goSyntax, depth
It's using the "reflect" package: http://golang.org/pkg/reflect/ to query the type of the argument. Inside p.printReflectValue
here: http://golang.org/src/pkg/fmt/print.go?h=printArg#L862 You will see the two cases where maps and structures are dealt with. It then uses recursion through printValue
to manage the contents.
Here's a bit of code that takes the reflection of a structure and then turns it back into another variable of the right type. You can't change from one arbitrary type to another using this, it has to be legal in go to cast the types from one to another without using reflection.
package main
import (
"fmt"
"reflect"
)
type Player string
type Board struct {
Tboard [9]string
Player1 Player
Player2 Player
}
// ignore this function contents, I grabbed it from elsewhere.
func makeBoard() *Board {
b := &Board{Tboard: [9]string{}}
for x := 0; x < len(b.Tboard); x++ {
b.Tboard[x] = "X"
fmt.Println(b.Tboard[x])
}
b.Player1 = "George"
b.Player2 = "Tim"
fmt.Printf("Len: %v\n", len(b.Tboard)) // => 9
fmt.Printf("Contents: %v\n", b)
fmt.Printf("Syntax: %#v\n", b)
fmt.Printf("Type: %T\n", b)
fmt.Println("Board:", b.Tboard)
return b
}
func main() {
myBoard := makeBoard()
v := reflect.ValueOf(*myBoard) // v is of type Value
t := v.Type()
fmt.Printf("Value: %v %T\n", v, v)
fmt.Printf("Type: %v %T\n", t, t)
// would be a switch
if t == reflect.TypeOf(*myBoard) {
var b2 Board
b2 = v.Interface().(Board) // cast the type interface{} into type Board
fmt.Printf("v converted back to: %#v\n", b2)
} else {
fmt.Printf("t is not recognized")
}
}
Notice that the type of v
is main.Board
, the full package name, not Board
.
Any structure you want to do this to, must have an exported type for reflection to work.