英文:
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 "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 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)
}
}
}
英文:
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 "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)
}
}
}
答案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("forEachValue: expected slice type, found %q", v.Kind().String()))
}
for i := 0; i < v.Len(); i++ {
val := v.Index(i).Interface()
f(i, val)
}
}
Then, you use it like this:
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)
}
}
答案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 (
"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)
}
}
}
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]
答案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 (
"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
}
not so graceful but works well
fmt.Println(In(1, []int(2, 1, 3)))
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论