如何在泛型函数中迭代传递的切片联合?(T没有核心类型)

huangapple go评论83阅读模式
英文:

How to iterate over a union of slices passed in a generic function? (T has no core type)

问题

我正在测试 Go 1.18 中的泛型,并查看了这个示例
我想重新创建该示例,但是希望能够传入一个 int 切片或 float 切片,并在函数中将切片中的所有元素相加。

当我尝试迭代切片时遇到了一些问题。这是我尝试的代码:

package main

import "fmt"

// NumberSlice 约束
type NumberSlice interface {
	[]int64 | []float64
}

func add[N NumberSlice](n N) {
	// 希望:遍历 n 并打印 v 的值
	for _, v := range n {
		fmt.Println(v)
	}
}

func main() {
	ints := []int64{1, 2}
	add(ints)
}

我得到了错误信息:

无法对 n 进行迭代(N 的类型受 NumberSlice 约束)(N 没有核心类型)

我该如何实现这个功能?

英文:

I am testing out generics in go 1.18 and took a look at this example.
I would like to recreate that example but instead be able to pass in a slice of int or slice of float instead, and in the function I'll just sum up everything in the slice.

This is when I ran into some issues just iterating the slice. This is what I tried:

package main

import "fmt"

// NumberSlice constraint
type NumberSlice interface {
	[]int64 | []float64
}

func add[N NumberSlice](n N) {
	// want: to range over n and print value of v 
	for _, v := range n {
		fmt.Println(v)
	}
}

func main() {
	ints := []int64{1, 2}
	add(ints)
}

I got the error:

> cannot range over n (variable of type N constrained by NumberSlice) (N has no core type)

How do I accomplish this?

答案1

得分: 9

一个核心类型,对于一个接口(包括接口约束),定义如下:

如果满足以下条件之一,接口T具有核心类型:

  • 存在一个单一类型U,它是T类型集中所有类型的底层类型

  • 或者T的类型集仅包含具有相同元素类型E的通道类型,并且所有定向通道具有相同的方向。

你的接口约束没有核心类型,因为它有两个底层类型:[]int64[]float64

因此,在需要核心类型的地方,你不能使用它。特别是rangemake

你可以将接口更改为要求基本类型,然后在函数签名中指定切片:

// 仍然没有核心类型...
type Number interface {
    int64 | float64
}

// ...但是参数将实例化为int64或float64
func add[N Number](n []N) {
    for _, v := range n {
        fmt.Println(v)
    }
}

这也可以工作,但更冗长:

type NumberSlice[N int64 | float64] interface {
    // 一个核心类型 []N
	~[]N
}

func add[S NumberSlice[N], N int64 | float64](n S) {
	for _, v := range n {
		fmt.Println(v)
	}
}
英文:

A core type, for an interface (including an interface constraint) is defined as follows:

> An interface T has a core type if one of the following conditions is
> satisfied:
>
> - There is a single type U which is the underlying type of all types in the type set of T
>
> - or the type set of T contains only channel types with identical element type E, and all directional channels have the same direction.

Your interface constraint has no core type, because it has two underlying types: []int64 and []float64.

Therefore you can't use it where a core type is required. Notably range and make.

You can change the interface to require the base types, and then specify the slice in the function signature:

// still no core type...
type Number interface {
    int64 | float64
}

// ...but the argument will be instantiated with either int64 or float64
func add[N Number](n []N) {
    for _, v := range n {
        fmt.Println(v)
    }
}

This also works, but it's way more verbose:

type NumberSlice[N int64 | float64] interface {
    // one core type []N
	~[]N
}

func add[S NumberSlice[N], N int64 | float64](n S) {
	for _, v := range n {
		fmt.Println(v)
	}
}

答案2

得分: 1

这样的代码对你有用吗?

package main

import "fmt"

type NumberOrFloat interface {
	int64 | float64
}

func add[N NumberOrFloat](n []N) {
	for _, v := range n {
		fmt.Println(v)
	}
}

func main() {
	ints := []int64{1, 2}
	add(ints)
}

这里的区别在于你对数组元素定义了类型约束(而不是数组类型):[]N

英文:

Could something like this work for you?

package main

import "fmt"

type NumberOrFloat interface {
	int64 | float64
}

func add[N NumberOrFloat](n []N) {
	for _, v := range n {
		fmt.Println(v)
	}
}

func main() {
	ints := []int64{1, 2}
	add(ints)
}

The difference here is that you define type constraints on array elements (not on array types): []N

huangapple
  • 本文由 发表于 2022年3月18日 01:36:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/71516746.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定