繁体   English   中英

Express function 可以任意切片

[英]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())
        //...
    }
}

请参阅https://play.golang.org/p/TyzT3lBEjB

现在有了 Go 1.18+,您可以使用generics功能来做到这一点:

func myFunc[T any](list []T) {
  for _, item := range list {
    doSomething(item)
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM