4

刚开始编写 Go 代码,我遇到了一个有趣的问题。

有没有一种方法可以轻松地迭代作为空接口引入的数组中的项目而无需重复代码?考虑以下:

function(someArr interface{}){
  switch someArr.(type){
    case []int :
        arr := (someArr).([]int)
        for i := range (arr) {
          // CODE
        }

    case []string :
        arr := (someArr).([]string)
        for i := range (arr) {
          // CODE
        }
  } 
}

在本例中,CODE 中的代码完全相同。但是,我不能将它从开关中取出,因为类型断言 arr 会超出范围。同样,我不能在 switch 之前定义 arr 因为我不知道它会是什么类型。这可能是做不到的。在那种情况下,当我使用不规则模式(一些整数数组、一些数组或字符串)解析 JSON 时,这种事情有什么更好的习惯用法?

4

2 回答 2

6

您可以使用反射包迭代任意切片。但是显式地实现特殊情况(如[]int)通常更快,并且通常是为了避免在常见情况下的反射。

package main

import "fmt"
import "reflect"

func foo(values interface{}) {
    rv := reflect.ValueOf(values)
    if rv.Kind() != reflect.Slice {
        return
    }
    n := rv.Len()
    for i := 0; i < n; i++ {
        value := rv.Index(i).Interface()
        fmt.Println(value)
    }
}

func main() {
    foo([]int{1, 3, 3, 7})
}

编辑:我不确定为什么有人对这个问题和我的回答投了反对票,但在某些情况下你需要处理这样的代码。甚至标准库也包含很多内容,例如“fmt”、“gob”、“json”、“xml”和“template”。提问者可能面临类似的问题。

于 2013-08-20T20:13:44.283 回答
6

您的示例不是惯用的 Go 代码,即使惯用的代码在词汇上似乎也违反了 DRY 原则。

要理解的关键点是 'x'在每种类型的情况下都是一个单独的、不同类型的变量:

function(someArr interface{}){
        switch x := someArr.(type) {
        case []int:
                for i := range x {
                        // CODE
                }
        case []string:
                for i := range x {
                        // CODE
                }
        }
}
于 2013-08-20T20:14:13.873 回答