【发布时间】:2021-04-13 13:14:15
【问题描述】:
如果我有一个函数传递了一个interface{},我可以确定(通过其他方式)是一个切片,但不能确定它是一个切片,我如何迭代它(最好不使用反射)?
这是一个 MCVE(从我的实际代码非常简化)。 forEach 是一个遍历 a 切片的函数,其类型在 main() 的调用堆栈中“丢失”。它试图说“啊哈,一个切片,我将遍历它一个interface{} 的切片并在每个值上调用传入的onEach 函数”。这失败了,因为“转换”类型因此失败:
panic: interface conversion: interface {} is []string, not []interface {}
我很清楚为什么类型“转换”会失败,即它不是真正的类型转换,而是一个断言。但是考虑到(如果我可以迭代)我可以断言每个切片成员,这原则上应该是可行的。
假设我实际上想要一个像 forEach 这样的迭代器,它可以做到这一点(而不是 forEachString、forEachInt 等)。有没有好的方法来做到这一点?最好没有反射(虽然我想这没关系),但肯定没有反射涉及每种类型的案例(这就是首先拥有forEach 函数的意义)?
我知道(尚未实施的)泛型提案对此非常有效,但我希望使用现有技术来做到这一点!
package main
import (
"fmt"
)
type onEach func(x interface{})
func printString(x interface{}) {
xx := x.(string)
fmt.Printf("x is a string '%s'\n", xx)
}
func printInt(x interface{}) {
xx := x.(int)
fmt.Printf("x is an int '%d'\n", xx)
}
func forEach(y interface{}, onEach onEach) {
// code to ensure y is a slice omitted
a := y.([]interface{}) // <-------- THIS LINE PANICS
for _, x := range a {
onEach(x)
}
}
func main() {
s := []string{"foo", "bar"}
i := []int{1, 2, 3}
forEach(s, printString)
forEach(i, printInt)
}
【问题讨论】:
-
您可以枚举所有可能的切片类型,也可以使用反射。没有别的办法。
-
@JimB 即使用
Value.Len()、Value.Index()等?我想这就是我必须做的 - 叹息。 -
@JimB OK - 用示例代码添加了一个答案,以防其他人需要这个。