表示任意切片的函数
Posted
技术标签:
【中文标题】表示任意切片的函数【英文标题】:Express function that takes any slice 【发布时间】:2017-08-16 16:27:16 【问题描述】:我想表达一个可以取任意切片的函数。我认为我可以这样做:
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 的表示是不同的。这个答案总结了为什么但是关于指向接口而不是接口切片的指针,但原因是一样的: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 行代码在我们的代码中是惯用的,而且输入错误很容易引入错误。我真的很想念泛型。真的没有办法吗?!!
【问题讨论】:
【参考方案1】:在您提供的情况下,您必须将切片创建为 interface
的切片,例如s := []interface
。此时您可以将任何您想要的类型放入切片中(甚至混合类型)。但是你必须做各种各样的类型断言,一切都变得非常糟糕。
解组器常用的另一种技术是这样的定义:
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")
【讨论】:
【参考方案2】:不,没有简单的方法来处理它。许多人在 Go 中怀念泛型。
也许你可以从sort.Sort
函数和sort.Interface
中得到启发,找到一个不需要复制切片的合理解决方案。
【讨论】:
【参考方案3】:最好的办法可能是定义一个接口,该接口封装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())
//...
见https://play.golang.org/p/TyzT3lBEjB。
【讨论】:
以上是关于表示任意切片的函数的主要内容,如果未能解决你的问题,请参考以下文章