迭代接口 [英] Iterate over an interface

查看:92
本文介绍了迭代接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建一个函数,该函数可以接受映射或任何其他数组,并遍历它调用每个项目上的函数,该函数知道如何处理遇到的任何类型。

这是我第一次失败的尝试。目前,当我在我的真实使用案例中运行它时,它总是说呃哦!。

$ func DoTheThingToAllTheThings(data_interface interface {} )int {
var numThings int

switch data:= data_interface。(type){
case map [interface {}] interface {}:
numThings = len (数据)
用于索引,item:=范围数据{
DoTheThing(index,item)
}
case [] interface {}:
numThings = len数据)
用于索引,项目:=范围数据{
DoTheThing(索引,项目)
}
默认值:
fmt.Println(呃哦!)
}

return numThings
}

数组或映射可能包含很多不同的东西,因此它不是一种尝试匹配每个可能的输入的选项。



换句话说,有没有办法在Go中迭代数组或映射而不知道它到底是什么?

fmt.Printf(%v \ n,data_interface)完全符合您的需求。它将打印传递给它的整个映射或数组。



你可以在这里找到实现:

接近 printArg 结尾的行是关键:

  return p.printReflectValue(reflect.ValueOf(arg),verb,plus,goSyntax,depth 

它使用反射包: http://golang.org/pkg/reflect/ 来查询参数的类型。在 p.printReflectValue 里面: http://golang.org/src/pkg/fmt/print.go?h=printArg#L862 您将看到两种情况:处理地图和结构,然后通过 printValue 递归来管理内容。



这里有一点代码ta kes是一个结构的反射,然后把它变成另一个正确类型的变量。你不能从一个任意类型转换到另一个类型,使用它必须是合法的,不必使用反射就可以将类型从一个类型转换到另一个类型。

 包主
$ b $导入(
fmt
反映


类型播放器字符串

类型Board结构{
Tboard [9] string
Player1 Player $ b $ Player2 Player
}

//忽略此功能内容,我从其他地方抓起来。
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(内容:%v \ n,b)
fmt.Printf(语法:%#v \ n,b)
fmt.Printf(Type:%T \\\
,b)
fmt.Println(Board:,b.Tboard)
return b
}

func main(){
myBoard:= makeBoard()

v:= reflect.ValueOf(* myBoard)// v的类型是Value
t:= v.Type ()

fmt.Printf(Value:%v%T \\\
,v,v)
fmt.Printf(Type:%v%T \\\
, t,t)

//如果t == reflect.TypeOf(* myBoard){
var b2 Board

b2将会是一个开关
= v.Interface()。(Board)//将类型interface {}转换为Board
fmt.Printf(v转换回:%#v \ n,b2)
} else {
fmt.Printf(t is not recognized)
}

}

请注意, v 的类型是 main.Board 名称,而不是电路板
您想要执行此操作的任何结构必须具有用于反射才能工作的导出类型。


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.

Stated otherwise, is there a way to iterate over an array or map in Go without knowing exactly what it is?

解决方案

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.

这篇关于迭代接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆