表示任意切片的函数

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。

【讨论】:

以上是关于表示任意切片的函数的主要内容,如果未能解决你的问题,请参考以下文章

tf.slice函数解析

Go 系列教程 —— 11. 数组和切片

Golang 切片

python基础-- 07 切片

go语言学习笔记 — 基础 — 高级数据类型 — 数据容器 — 切片:切片的初始化声明

实现python切片表示法