[英]How to express type of “slice of (string or 'other such slice')”
[英]Express function that takes any slice
我想表达一个可以取任何切片的 function。 我认为我可以这样做:
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 ,其中指出 []interface{} 的表示是不同的。 这个答案总结了为什么但是关于指向接口的指针而不是接口切片,但原因是一样的: 为什么我不能将 *Struct 分配给 *Interface? .
上面 golang.org 链接提供的建议建议从DEFINITE_TYPE
切片重建一个新的接口切片。 但是,在我想调用这个 function 的代码中的任何地方都这样做是不切实际的(这个 function 本身意味着只缩写 9 行代码,但是这 9 行在我们的代码中出现的频率很高)。
在我想调用 function 的每种情况下,我都会传递一个[]*DEFINITE_TYPE
,我起初认为它更容易抽象,直到我再次发现为什么我不能将 *Struct 分配给 *Interface? (上面也有链接)。
此外,每次我想调用 function 时,它使用不同的DEFINITE_TYPE
,因此为 n 类型实现 n 示例不会为我节省任何代码行或使我的代码更清晰(恰恰相反。)。
令人沮丧的是我不能这样做,因为这 9 行代码在我们的代码中是惯用的,而且输入错误很容易引入错误。 我真的很想念generics。 真的没有办法吗?!!
在您提供的情况下,您必须将切片创建为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")
}
}
没有没有简单的方法来处理它。 很多人都错过了Go中的仿制药。
也许你可以通过sort.Sort
函数和sort.Interface
获得灵感,找到一个不需要复制切片的合理解决方案。
可能最好的做法是定义一个接口,该接口封装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())
//...
}
}
现在有了 Go 1.18+,您可以使用generics功能来做到这一点:
func myFunc[T any](list []T) {
for _, item := range list {
doSomething(item)
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.