编写对泛型类型进行操作的方法的惯用方式

时间:2019-06-20 02:41:15

标签: go generics slice

编写在“通用”数组上运行的方法的惯用方式是什么?

我有一个类型化数组:

a := make([]int, 0)

我想写一个可以对任何类型的数组进行操作的简单方法:

func reverse(a []interface{}) []interface{} {
    for i, j := 0, len(a)-1; i < j; i, j = i+1, j-1 {
        a[i], a[j] = a[j], a[i]
    }
    return a
}

使用此方法a = reverse(a)会给我两个错误:

cannot use a (type []int) as type []interface {} in argument to reverse
cannot use reverse(a) (type []interface {}) as type []int in assignment

3 个答案:

答案 0 :(得分:2)

耐心!根据该语言的latest draft proposal to add type parameters,您将能够在以后的Go版本中编写这样一个通用的reverse函数:

func reverse[T any](s []T) []T {
    for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
        s[i], s[j] = s[j], s[i]
    }
    return s
}

func main() {
    s := []int{1, 2, 3, 4, 5}
    s = reverse(s)
    fmt.Println(s)
}

playground

答案 1 :(得分:2)

并不是说您现在就可以在生产中使用泛型(从2020年10月2日开始),但是对于对即将到来的go泛型功能感兴趣的人来说,最新的design draft是go,您可以编写泛型函数{ {1}}如下

reverse

输出:

package main

import (
    "fmt"
)

func reverse[T any](s []T) []T {
    for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
        s[i], s[j] = s[j], s[i]
    }
    return s
}

func main() {
    s := []int{1, 2, 3, 4, 5}
    s = reverse(s)
    fmt.Println(s)
}

答案 2 :(得分:1)

直到泛型出现(很可能称为contracts),反射和接口是实现这种泛化的唯一工具。

您可以定义reverse()来获取interface{}的值,并使用reflect包对其进行索引并交换元素。这通常很慢,并且很难阅读/维护。

接口提供了一种更好的方法,但是需要您将方法编写为不同的类型。看一下sort包,特别是sort.Sort()函数:

func Sort(data Interface)

sort.Interface在哪里:

type Interface interface {
        // Len is the number of elements in the collection.
        Len() int
        // Less reports whether the element with
        // index i should sort before the element with index j.
        Less(i, j int) bool
        // Swap swaps the elements with indexes i and j.
        Swap(i, j int)
}

sort.Sort()可以对实现sort.Interface的任何切片进行排序,这些切片具有排序算法执行其工作所需的方法。这种方法的优点在于,您不仅可以对切片(例如,链表或数组)进行排序,还可以对其他数据结构进行排序。