我想表达一个可以采取任何切片的函数.我以为我可以这样做:
func myFunc(list []interface{}) {
for _, i := range list {
...
some_other_fun(i)
...
}
}
Run Code Online (Sandbox Code Playgroud)
它some_other_fun(..)本身就是一种interface{}类型.然而,这并不能工作,因为你无法通过[]DEFINITE_TYPE的[]interface{}.请参阅:https://golang.org/doc/faq#convert_slice_of_interface,其中指出[]接口{}的表示形式不同.这个答案总结了为什么,但是关于接口指针而不是接口切片,但原因是相同的:为什么我不能将*Struct分配给*接口?.
上面golang.org链接中提供的建议建议从DEFINITE_TYPE切片重建新的接口切片.但是,在我想要调用此函数的代码中到处都是不实际的(这个函数本身只是缩写9行代码,但是这9行在我们的代码中经常出现).
在我想要调用函数的每种情况下,我都会传递一个[]*DEFINITE_TYPE我最初认为更容易抽象的东西,直到我再次发现为什么我不能为*接口分配*Struct?(也在上面链接).
此外,每次我想调用它的功能都是不同的,DEFINITE_TYPE因此实现n个类型的n个示例不会为我节省任何代码行或使我的代码更清晰(恰恰相反!).
令人沮丧的是,我无法做到这一点,因为我们的代码中的9行是惯用的,而错误的类型很容易引入错误.我真的错过了泛型.有没有办法做到这一点?!!
在您提供的情况下,您必须创建切片作为interface例如s := []interface{}{}.在这一点上,你可以将任何你想要的类型放入切片中(甚至是混合类型).但是你必须做各种类型的断言,一切都变得非常讨厌.
unmarshalers常用的另一种技术是这样的定义:
func myFunc(list interface{})
Run Code Online (Sandbox Code Playgroud)
因为切片适合interface,所以您确实可以将常规切片传递给它.您仍然需要进行一些验证并输入断言myFunc,但是您将在整个列表类型上执行单个断言,而不必担心可能包含混合类型的列表.
无论哪种方式,由于是静态类型语言,您最终必须知道通过断言传递的类型.这就是事情的方式.在你的情况下,我可能会使用上面的func签名,然后使用类型开关来处理不同的情况.请参阅此文档https://newfivefour.com/golang-interface-type-assertions-switch.html
所以,像这样:
func myFunc(list interface{}) {
switch v := list.(type) {
case []string:
// do string thing
case []int32, []int64:
// do int thing
case []SomeCustomType:
// do SomeCustomType thing
default:
fmt.Println("unknown")
}
}
Run Code Online (Sandbox Code Playgroud)
也许最好的办法是定义一个接口来封装需要myFunc对切片执行的操作(即,在您的示例中,获取第 n 个元素)。然后函数的参数是接口类型,并且您为要传递给函数的每种类型定义接口方法。
您也可以使用reflect包来完成此操作,但这可能不是一个好主意,因为如果您传递除切片(或数组或字符串)之外的其他内容,它会出现恐慌。
func myFunc(list interface{}) {
listVal := reflect.ValueOf(list)
for i := 0; i < listVal.Len(); i++ {
//...
some_other_fun(listVal.Index(i).Interface())
//...
}
}
Run Code Online (Sandbox Code Playgroud)
请参阅https://play.golang.org/p/TyzT3lBEjB。