Iterate over an interface

后端 未结 2 956
面向向阳花
面向向阳花 2020-12-04 00:56

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

相关标签:
2条回答
  • 2020-12-04 01:29

    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?".

    0 讨论(0)
  • 2020-12-04 01:43

    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.

    0 讨论(0)
提交回复
热议问题