接收函数参数中的任何数组类型

时间:2018-10-14 16:09:50

标签: arrays go

我刚开始玩Go。我开始创建一个接受整数数组并返回该数组的块的函数。要明白我的意思,这里是该程序:

package main

import (
    "fmt"
    "math"
)

func main() {
    a:= []int{1,2,3,4,5,6,2, 231, 521,21, 51}

    c:=chunks(a[:], 3)
    fmt.Println(c) // [[1 2 3] [4 5 6] [2 231 521] [51]]
}

func chunks(a []int, size int) [][]int{
    var f float64 = float64(len(a)) / float64(size)
    size_of_wrapper := int(math.Ceil(f))
    i := 0
    j := 0
    twoD := make([][]int, size_of_wrapper )

    for i < len(a) {
        if i + size < len(a) {
            twoD[j] = make([]int, size)
            twoD[j] = append(a[i:i+size])
            i = i + size
            j++
        } else {
                if i + size == len(a){
                i++
            } else {
                twoD[j] = make([]int, 1)
                    twoD[j] = append(a[len(a)-1:])
                i++
            }

        }
    }

    return twoD 
}

现在,我有一个问题。我是否可以启用此函数以接收包含字符串或任何其他类型的数组?另外,我可以设置最后返回相同类型吗?在这种情况下,我将返回一个仅包含整数值的数组。

我似乎真的很难找到解决这个问题的方法。我读过的其中一篇文章建议将接口类型用于此类工作。那是唯一的吗?

2 个答案:

答案 0 :(得分:1)

  

我可以启用此功能以接收包含字符串或任何其他类型的数组吗?   另外,我可以设置最后返回相同类型吗?我

不幸的是,Go编程语言没有泛型。 AFAIK Go在下一个2.0版本中将具有泛型,因此现在您主要有3个也许是4个选项。

1。使用[]interface{}类型

您的函数声明将如下所示。

func chunks(a []interface{}, size int) [][]interface{}

使用这种方法将暗示一些type assertion

2。使用reflect程序包

定义将看起来相同,但是这次在您的实现中,而不是使用类型断言技术,您将使用反射包来确定您的类型并检索值。请记住,您将pay a reasonable cost使用这种方法。

3。使用一些不安全的指针魔术。

您可以使用此通用指针类型,并以C精神进行一些指针运算。

func chunks(a unsafe.Pointer, len uintptr, size uintptr) unsafe.Pointer

我知道,如果您搜索Go并不 正式 ,但是您可以使用以下方法 伪造 这样的技巧。

package main

import "fmt"
import "unsafe"

func main() {
    vals := []int{10, 20, 30, 40}
    start := unsafe.Pointer(&vals[0])
    size := unsafe.Sizeof(int(0))
    for i := 0; i < len(vals); i++ {
        item := *(*int)(unsafe.Pointer(uintptr(start) + size*uintptr(i)))
        fmt.Println(item)
    }
}

4。在构建阶段尝试使用go generate

您可以找到more information,了解如何根据您提供的类型生成go代码。

答案 1 :(得分:1)

因为Go还没有通用名称,所以选项是对每种类型使用反射或重复代码。以下是使用reflect软件包的方法:

// chunkAny slices a into size chunks and puts result in cp. 
// The variable cp must be pointer to slice of a's type.
func chunkAny(a interface{}, size int, cp interface{}) {
    av := reflect.ValueOf(a)
    cv := reflect.ValueOf(cp).Elem()
    cv.SetLen(0) // reset length in case backing array allocated
    i, j := 0, size
    for j < av.Len() {
        cv.Set(reflect.Append(cv, av.Slice(i, j)))
        i += size
        j += size
    }
    cv.Set(reflect.Append(cv, av.Slice(i, av.Len())))
}

这样调用函数:

a := []string{"a", "b", "c", "d"}
var b [][]string
chunkAny(a, 3, &b)

Run it on the playground