遍历存储切片的interface{}类型的范围

huangapple go评论86阅读模式
英文:

range over interface{} which stores a slice

问题

给定一个情景,你有一个接受t interface{}的函数。如果确定t是一个切片,我该如何遍历这个切片?

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:
        // 在这里我该如何迭代?
        for _,value := range t {
            fmt.Println(value)
        }
    }
}

Go Playground 示例:http://play.golang.org/p/DNldAlNShB

英文:

Given the scenario where you have a function which accepts t interface{}. If it is determined that the t is a slice, how do I range over that slice?

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)
		}
	}
}

Go Playground Example: http://play.golang.org/p/DNldAlNShB

答案1

得分: 182

好的,以下是翻译好的部分:

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))
        }
    }
}

Go Playground 示例:http://play.golang.org/p/gQhCTiwPAq

英文:

Well I used reflect.ValueOf and then if it is a slice you can call Len() and Index() on the value to get the len of the slice and element at an index. I don't think you will be able to use the range operate to do this.

package main

import &quot;fmt&quot;
import &quot;reflect&quot;

func main() {
    data := []string{&quot;one&quot;,&quot;two&quot;,&quot;three&quot;}
    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 &lt; s.Len(); i++ {
            fmt.Println(s.Index(i))
        }
    }
}

Go Playground Example: http://play.golang.org/p/gQhCTiwPAq

答案2

得分: 37

你知道要期望哪些类型时,就不需要使用反射。你可以使用type switch,像这样:

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)
        }
    }
}

在playground上查看代码

英文:

You don't need to use reflection if you know which types to expect. You can use a type switch, like this:

package main

import &quot;fmt&quot;

func main() {
    loop([]string{&quot;one&quot;, &quot;two&quot;, &quot;three&quot;})
    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)
        }
    }
}

Check out the code on the playground.

答案3

得分: 4

根据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: 期望切片类型,找到 %q", v.Kind().String()))
	}

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

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

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)
    }
}
英文:

Expanding on the answer provided by masebase, you could generalize the iteration on an interface{} slice with a function like this:

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(&quot;forEachValue: expected slice type, found %q&quot;, v.Kind().String()))
	}

	for i := 0; i &lt; v.Len(); i++ {
		val := v.Index(i).Interface()
		f(i, val)
	}
}

Then, you use it like this:

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

func test(sliceIface interface{}) {
    forEachValue(sliceIface, func(i int, value interface{}) {
      fmt.Println(value)
    }
}

答案4

得分: 3

有一种情况与interface{}的行为不同,@Jeremy Wall已经给出了指针。如果传递的数据最初被定义为[]interface{}。

package main

import (
	"fmt"
)

type interfaceSliceType []interface{}

var interfaceAsSlice interfaceSliceType

func main() {
	loop(append(interfaceAsSlice, 1, 2, 3))
	loop(append(interfaceAsSlice, "1", "2", "3"))
	// or
	loop([]interface{}{[]string{"1"}, []string{"2"}, []string{"3"}})
    fmt.Println("------------------")


    // and of course one such slice can hold any type
    loop(interfaceSliceType{"string", 999, map[int]string{3: "three"}})
}

func loop(slice []interface{}) {
	for _, elem := range slice {
		switch elemTyped := elem.(type) {
		case int:
			fmt.Println("int:", elemTyped)
		case string:
			fmt.Println("string:", elemTyped)
		case []string:
			fmt.Println("[]string:", elemTyped)
	    case interface{}:
		    fmt.Println("map:", elemTyped)
		}
	}
}

输出:

int: 1
int: 2
int: 3
string: 1
string: 2
string: 3
[]string: [1]
[]string: [2]
[]string: [3]
------------------
string: string
int: 999
map: map[3:three]
英文:

there is one exception from the way interface{} behaves, @Jeremy Wall gave already pointer. if the passed data is defined as []interface{} initially.

package main

import (
	&quot;fmt&quot;
)

type interfaceSliceType []interface{}

var interfaceAsSlice interfaceSliceType

func main() {
	loop(append(interfaceAsSlice, 1, 2, 3))
	loop(append(interfaceAsSlice, &quot;1&quot;, &quot;2&quot;, &quot;3&quot;))
	// or
	loop([]interface{}{[]string{&quot;1&quot;}, []string{&quot;2&quot;}, []string{&quot;3&quot;}})
    fmt.Println(&quot;------------------&quot;)


    // and of course one such slice can hold any type
    loop(interfaceSliceType{&quot;string&quot;, 999, map[int]string{3: &quot;three&quot;}})
}

func loop(slice []interface{}) {
	for _, elem := range slice {
		switch elemTyped := elem.(type) {
		case int:
			fmt.Println(&quot;int:&quot;, elemTyped)
		case string:
			fmt.Println(&quot;string:&quot;, elemTyped)
		case []string:
			fmt.Println(&quot;[]string:&quot;, elemTyped)
	    case interface{}:
		    fmt.Println(&quot;map:&quot;, elemTyped)
		}
	}
}

output:

int: 1
int: 2
int: 3
string: 1
string: 2
string: 3
[]string: [1]
[]string: [2]
[]string: [3]
------------------
string: string
int: 999
map: map[3:three]

try it out

答案5

得分: 0

一个常见的函数

import (
	"fmt"
	"reflect"
)

func In(item interface{}, list interface{}) (ret bool, err error) {
	defer func() {
		if r := recover(); r != nil {
			ret, err = false, fmt.Errorf("%v", r)
		}
	}()
	itemValue, listValue := reflect.ValueOf(item), reflect.ValueOf(list)
	for i := 0; i < listValue.Len(); i++ {
		if listValue.Index(i).Interface() == itemValue.Interface() {
			return true, nil
		}
	}
	return false, nil
}

不太优雅但功能良好

fmt.Println(In(1, []int{2, 1, 3}))
英文:

a common in function

import (
	&quot;fmt&quot;
	&quot;reflect&quot;
)

func In(item interface{}, list interface{}) (ret bool, err error) {
	defer func() {
		if r := recover(); r != nil {
			ret, err = false, fmt.Errorf(&quot;%v&quot;, r)
		}
	}()
	itemValue, listValue := reflect.ValueOf(item), reflect.ValueOf(list)
	for i := 0; i &lt; listValue.Len(); i++ {
		if listValue.Index(i).Interface() == itemValue.Interface() {
			return true, nil
		}
	}
	return false, nil
}

not so graceful but works well

fmt.Println(In(1, []int(2, 1, 3)))

huangapple
  • 本文由 发表于 2012年12月25日 05:28:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/14025833.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定