猿问

如何在同一个函数中接受不同类型的切片?

我有一个removeFrom从切片中删除项目的功能。它接受一个float64切片和一个索引:


func removeFrom(slice []float64, index int) []float64 {

    if len(slice) > index {

        return append(slice[:index], slice[index+1:]...)

    }

}

它工作正常,但现在我也必须从整数切片中删除。那么我怎么能改变它以接受这两种类型(并返回给定类型的切片)?我尝试使用空接口,但显然我必须在函数内部进行一些转换,但我不知道该怎么做。


慕莱坞森
浏览 123回答 2
2回答

四季花海

简短的回答?你不能。长答案,你仍然不能直接这样做,但是:func removeFrom(slice interface{}, index int) interface{} {    switch slice := slice.(type) {    case []float64:        if len(slice) > index {            return append(slice[:index], slice[index+1:]...)        }    case []int64:        if len(slice) > index {            return append(slice[:index], slice[index+1:]...)        }    case []int:        if len(slice) > index {            return append(slice[:index], slice[index+1:]...)        }    default:        log.Panicf("unknown type: %T", slice)    }}

catspeake

Go 不支持泛型,所有切片类型都没有“共同祖先”(例如,[]interface{}与“不兼容” []int,请参阅无法将 []string 转换为 []interface {}了解更多详细信息)。因此,如果您希望您的函数接受任何切片类型,则必须使用interface{}(对于“传入”参数和返回类型)。但是现在您有一个(接口)包装器值,您不能对其应用切片,也不能将其传递给内置append()函数。您可以对已知类型使用类型断言和类型开关,但是您必须为每个类型重复代码,所以这并不是真正的领先一步。实际上,有一种方法可以removeFrom()使用反射创建一个适用于所有切片类型的函数。reflect.Value是一种描述任何 Go 值的类型。它为不同类型的 Go 值提供支持方法,包括切片。我们感兴趣的是Value.Slice()方法:func (v Value) Slice(i, j int) Value我们可以用它来切片。好的。这是我们的元素去除算法中的一个关键点。仍然需要“加入”2 个切片,即可移动元素之前的切片和可移动元素之后的切片。幸运的是,这个reflect包也支持这个reflect.AppendSlice()::func AppendSlice(s, t Value) Value作为最后剩下的键,我们可以Value.Len()用来获取任何切片的长度。我们现在拥有了我们的一般removeFrom()功能所需的一切,这非常简单:func removeFrom(s interface{}, idx int) interface{} {&nbsp; &nbsp; if v := reflect.ValueOf(s); v.Len() > idx {&nbsp; &nbsp; &nbsp; &nbsp; return reflect.AppendSlice(v.Slice(0, idx), v.Slice(idx+1, v.Len())).Interface()&nbsp; &nbsp; }&nbsp; &nbsp; return s}真的,仅此而已。测试它:for i := 0; i < 4; i++ {&nbsp; &nbsp; fmt.Println(removeFrom([]int{0, 1, 2}, i), "missing:", i)}for i := 0; i < 4; i++ {&nbsp; &nbsp; fmt.Println(removeFrom([]string{"zero", "one", "two"}, i), "missing:", i)}输出(在Go Playground上试试):[1 2] missing: 0[0 2] missing: 1[0 1] missing: 2[0 1 2] missing: 3[one two] missing: 0[zero two] missing: 1[zero one] missing: 2[zero one two] missing: 3笔记:该解决方案使用反射,因此它比不使用反射但具有“连接”的具体支持类型的另一个解决方案要慢。快速基准测试表明,这种通用解决方案比有线输入类型的非反射慢 2.5 倍。应该权衡性能或便利性/通用解决方案是否更重要。或者你可以将它与具体类型结合起来:你可以添加一个类型开关来处理频繁的类型,并且只有在类型开关没有处理实际的具体类型时才恢复到这个通用解决方案。
随时随地看视频慕课网APP

相关分类

Go
我要回答