存储切片的接口{}上的范围

Nuc*_*eon 76 reflection go slice go-reflect

鉴于你有一个接受的功能的场景t interface{}.如果确定t是切片,我range该如何切片?我不会知道传入的类型,例如[]string,[]int或者[]MyType,在编译时.

func main() {
    data := []string{"one","two","three"}
    test(data)
    moredata := []int{1,2,3}
    test(data)
}

func test(t interface{}) {
    switch reflect.TypeOf(t).Kind() {
    case reflect.Slice:
        // how do I iterate here?
        for _,value := range t {
            fmt.Println(value)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

去游乐场示例:http://play.golang.org/p/DNldAlNShB

mas*_*ase 114

好吧,我使用reflect.ValueOf然后如果它是一个切片,你可以调用Len()Index()值来获取len索引处的切片和元素.我不认为您将能够使用范围操作来执行此操作.

package main

import "fmt"
import "reflect"

func main() {
    data := []string{"one","two","three"}
    test(data)
    moredata := []int{1,2,3}
    test(moredata)
} 

func test(t interface{}) {
    switch reflect.TypeOf(t).Kind() {
    case reflect.Slice:
        s := reflect.ValueOf(t)

        for i := 0; i < s.Len(); i++ {
            fmt.Println(s.Index(i))
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

去游乐场示例:http://play.golang.org/p/gQhCTiwPAq

  • 工作得很好,谢谢.唯一要补充的是`s.Index(i)`返回一个`reflect.Value`所以在我的情况下我需要`s.Index(i).Interface()`来引用实际值. (21认同)
  • 回答我的问题:如果您有一个指向切片而不是切片的指针,则需要使用“Elem()”来获取基础值。例如 `reflect.TypeOf(reflect.ValueOf(t).Elem().Interface()).Kind()` (2认同)

Ina*_*mus 16

如果您知道要使用哪种类型,则无需使用反射.您可以使用类型开关,如下所示:

package main

import "fmt"

func main() {
    loop([]string{"one", "two", "three"})
    loop([]int{1, 2, 3})
}

func loop(t interface{}) {
    switch t := t.(type) {
    case []string:
        for _, value := range t {
            fmt.Println(value)
        }
    case []int:
        for _, value := range t {
            fmt.Println(value)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

看看操场上的代码.

  • 但数组的类型将取决于它的实际容量。[3]int 与 [2]int 或 []int 不是同一类型。因此,如果“t”的类型实际上是数组,则相关情况将不适用。 (2认同)
  • 我的意思是你的例子不适用于数组。我在这里更改了它:https://play.golang.org/p/DAsg_0aXz-r (2认同)

tot*_*rio 5

扩展 masebase 提供的答案,您可以interface{}使用如下函数概括切片上的迭代:

func forEachValue(ifaceSlice interface{}, f func(i int, val interface{})) {
    v := reflect.ValueOf(ifaceSlice)
    if v.Kind() == reflect.Ptr {
        v = v.Elem()
    }
    if v.Kind() != reflect.Slice {
        panic(fmt.Errorf("forEachValue: expected slice type, found %q", v.Kind().String()))
    }

    for i := 0; i < v.Len(); i++ {
        val := v.Index(i).Interface()
        f(i, val)
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以像这样使用它:

func main() {
    data := []string{"one","two","three"}
    test(data)
    moredata := []int{1,2,3}
    test(data)
}

func test(sliceIface interface{}) {
    forEachValue(sliceIface, func(i int, value interface{}) {
      fmt.Println(value)
    }
}
Run Code Online (Sandbox Code Playgroud)