我想表达一个可以采取任何切片的函数。我以为我可以这样做:
func myFunc(list []interface{}) {
for _, i := range list {
...
some_other_fun(i)
...
}
}
其中some_other_fun(..)
本身采用interface{}
类型。但是,这不起作用,因为您无法将[]DEFINITE_TYPE
作为[]interface{}
传递。请参阅:https://golang.org/doc/faq#convert_slice_of_interface,其中指出[]接口{}的表示形式不同。这个答案总结了为什么,但是关于接口指针而不是接口切片,但原因是相同的:Why can't I assign a *Struct to an *Interface?。
上面golang.org链接中提供的建议建议从DEFINITE_TYPE
切片重建新的接口切片。但是,在我想要调用此函数的代码中到处都是不实际的(这个函数本身只是缩写9行代码,但是这9行代码在我们的代码中经常出现)。
在我想要调用函数的每种情况下,我都会传递一个[]*DEFINITE_TYPE
,我最初认为它更容易抽象,直到我再次发现Why can't I assign a *Struct to an *Interface?(上面也链接过)。
此外,每次我想调用函数时,它都使用不同的DEFINITE_TYPE
,因此为n个类型实现n个示例不会保存任何代码行或使我的代码更清晰(恰恰相反!)
令人沮丧的是,我无法做到这一点,因为我们的代码中有9行是惯用语,错误类型很容易引入错误。我真的错过了泛型。真的没有办法做到这一点吗?!!
答案 0 :(得分:6)
在您提供的情况下,您必须将切片创建为interface
的切片,例如s := []interface{}{}
。在这一点上,你可以将任何你想要的类型放入切片中(甚至是混合类型)。但是你必须做各种类型的断言,一切都变得非常讨厌。
unmarshalers常用的另一种技术是这样的定义:
func myFunc(list interface{})
因为切片适合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")
}
}
答案 1 :(得分:4)
没有简单的方法来处理它。许多人在Go中错过了仿制药。
也许你可以通过sort.Sort
函数和sort.Interface
获得灵感,找到一个不需要复制切片的合理解决方案。
答案 2 :(得分:1)
可能最好的做法是定义一个接口,该接口封装了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())
//...
}
}