Go类型开关中的代码复制

时间:2013-08-20 20:05:18

标签: go

刚开始编写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将超出范围。同样,我无法在切换之前定义arr,因为我不知道它将是什么类型。这可能无法完成。在那种情况下,当我使用不规则的模式(某些数组的int,某些数组或字符串)解析JSON时,这种事情的更好的习惯是什么?

2 个答案:

答案 0 :(得分:6)

您可以使用reflect包来迭代任意切片。但是,明确地实现特殊情况(如[]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”等。提问者可能会遇到类似的问题。

答案 1 :(得分:6)

你的例子不是惯用的Go代码,即使惯用的 lexically 似乎也违反了DRY原则。

要理解的关键点是'x'是单独的,在每种类型的情况下输入不同的变量:

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