迭代一个接口 [英] Iterate over an interface
问题描述
我想创建一个函数,它接受一个映射或一个数组,并迭代它,在每个项目上调用一个函数,该函数知道如何处理遇到的任何类型.
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 it encounters.
这是我第一次失败的尝试.目前,当我在实际用例中运行它时,它总是说哦哦!".
Here's my first failed attempt. Currently when I run it in my real use case it always says "uh oh!".
func DoTheThingToAllTheThings(data_interface interface{}) int {
var numThings int
switch data := data_interface.(type) {
case map[interface{}]interface{}:
numThings = len(data)
for index, item := range data {
DoTheThing(index, item)
}
case []interface{}:
numThings = len(data)
for index, item := range data {
DoTheThing(index, item)
}
default:
fmt.Println("uh oh!")
}
return numThings
}
数组或映射可能包含许多不同的内容,因此尝试匹配所有可能的输入并不是一种选择.
The array or map could contain lots of different things so it isn't an option to try and match every possible input.
另外说明,有没有办法在不确切知道它是什么的情况下在 Go 中迭代数组或映射?
推荐答案
fmt.Printf("%v
", data_interface)
函数完全符合您的要求.它将打印传递给它的整个地图或数组.
The function fmt.Printf("%v
", data_interface)
does exactly what you want. It will print the whole map or array passed to it.
你可以在这里找到实现:http://golang.org/src/pkg/fmt/print.go?h=printArg#L708
You can find the implementation here: http://golang.org/src/pkg/fmt/print.go?h=printArg#L708
靠近printArg
结尾的那一行是关键:
The line near the end of printArg
is key:
return p.printReflectValue(reflect.ValueOf(arg), verb, plus, goSyntax, depth
它正在使用reflect"包:http://golang.org/pkg/reflect/ 查询参数的类型.在 p.printReflectValue
里面:http://golang.org/src/pkg/fmt/print.go?h=printArg#L862 您将看到处理地图和结构的两种情况.然后通过printValue
使用递归来管理内容.
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.
这里有一些代码,它获取结构的反射,然后将其转换回正确类型的另一个变量.你不能使用 this 从一种任意类型更改为另一种类型,在不使用反射的情况下将类型从一种类型转换为另一种类型必须是合法的.
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
", len(b.Tboard)) // => 9
fmt.Printf("Contents: %v
", b)
fmt.Printf("Syntax: %#v
", b)
fmt.Printf("Type: %T
", 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
", v, v)
fmt.Printf("Type: %v %T
", 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
", b2)
} else {
fmt.Printf("t is not recognized")
}
}
注意v
的类型是main.Board
,完整的包名,而不是Board
.您想要执行此操作的任何结构都必须具有导出类型才能使反射工作.
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.
这篇关于迭代一个接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!