如何在Go语言中为泛型参数编写函数?

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

How to write func for the generic parameter in golang

问题

我正在尝试编写一个名为Map的函数,以便它可以处理所有类型的数组。

// 用于指定数组的通用类型的接口。
type Iterable interface {
}

func main() {
    list_1 := []int{1, 2, 3, 4}
    list_2 := []uint8{'a', 'b', 'c', 'd'}
    Map(list_1)
    Map(list_2)
}

// 这个函数打印所有[]types类型数组的每个元素。
func Map(list Iterable) {
    for _, value := range list {
        fmt.Print(value)
    }
}

但是它抛出了编译时错误。

19: cannot range over list (type Iterable)

这个错误是正确的,因为range需要数组、指向数组的指针、切片、字符串、映射或允许接收操作的通道,而这里的类型是Iterable。我认为我面临的问题是将参数类型Iterable转换为数组类型。请建议我如何使用我的函数来处理通用数组。

英文:

I am trying to write a function Map, so that it can handle all the types of array.

// Interface to specify generic type of array.
type Iterable interface {
}

func main() {
	list_1 := []int{1, 2, 3, 4}
	list_2 := []uint8{'a', 'b', 'c', 'd'}
	Map(list_1)
	Map(list_2)
}

// This function prints the every element for
// all []types of array.
func Map(list Iterable) {
	for _, value := range list {
		fmt.Print(value)
	}
}

But it throws the compile time error.

19: cannot range over list (type Iterable)

The error is correct because range require array, pointer to an array, slice, string, map, or channel permitting receive operations and here type is Iterable. I think problem that I am facing is, conversion of the argument type Iterable to array type. Please suggest, how could I use my function to handle generic array.

答案1

得分: 9

如Rob Pike在这个帖子中提到的:

> > 是否可以在Go类型开关中表示“任何映射”,“任何数组”或“任何切片”?
>
> 不行。静态类型必须完全匹配
空接口实际上是一种类型,而不是通配符。

你只能迭代特定类型的列表,比如具有已知函数的接口。
你可以参考“我们能在Go中编写通用的数组/切片去重吗?”的示例。

即使使用反射,将切片传递为interface{}也会出现错误,如这个帖子所示,可以看到这个示例


2021年11月更新,7年后:CL 363434,用于Go 1.18(2022年第一季度),实际上引入了对任何类型的切片有用的函数,使用了泛型

// Package slices defines various functions useful with slices of any type.
// Unless otherwise specified, these functions all apply to the elements
// of a slice at index 0 <= i < len(s).
package slices
import "golang.org/x/exp/constraints"
// Equal reports whether two slices are equal: the same length and all
// elements equal. If the lengths are different, Equal returns false.
// Otherwise, the elements are compared in index order, and the
// comparison stops at the first unequal pair.
// Floating point NaNs are not considered equal.
func Equal[T comparable](s1, s2 []T) bool {
	if len(s1) != len(s2) {
		return false
	}
	for i, v1 := range s1 {
		v2 := s2[i]
		if v1 != v2 {
			return false
		}
	}
	return true
}

请注意,问题 50792CL 382834 表明:

> 我们在标准库中放弃了constraints,因为我们认为它是使用泛型的基础,但实际上并非如此。
>
> 特别是,大多数代码使用anycomparable
如果这些是唯一的常见约束条件,也许我们不需要该包。
或者如果constraints.Ordered是唯一的其他常用约束条件,也许它应该是与anycomparable并列的预声明标识符。

因此,使用import "golang.org/x/exp/constraints"而不是import "constraints"

英文:

As Rob Pike mentions in this thread

> > Is it possible to express "any map", "any array" or "any slice" in a Go type switch?
>
> No. The static types must be exact.
The empty interface is really a type, not a wildcard.

You only could iterate over a list of a specific type, like an interface with known functions.
You can see an example with "Can we write a generic array/slice deduplication in go?"

Even using reflection, to pass a slice as an interface{} would be, as this thread shows, error-prone (see this example).


Update Nov. 2021, 7 years later: CL 363434, for Go 1.18 (Q1 2022) actually introduces functions useful with slices of any type, using generics.

// Package slices defines various functions useful with slices of any type.
// Unless otherwise specified, these functions all apply to the elements
// of a slice at index 0 <= i < len(s).
package slices
import "golang.org/x/exp/constraints"
// Equal reports whether two slices are equal: the same length and all
// elements equal. If the lengths are different, Equal returns false.
// Otherwise, the elements are compared in index order, and the
// comparison stops at the first unequal pair.
// Floating point NaNs are not considered equal.
func Equal[T comparable](s1, s2 []T) bool {
	if len(s1) != len(s2) {
		return false
	}
	for i, v1 := range s1 {
		v2 := s2[i]
		if v1 != v2 {
			return false
		}
	}
	return true
}

Note that issue 50792 and CL 382834 show that:

> We left constraints behind in the standard library because we believed it was fundamental to using generics, but in practice that hasn't proven to be the case.
>
> In particular, most code uses any or comparable.
If those are the only common constraints, maybe we don't need the package.
Or if constraints.Ordered is the only other commonly used constraint, maybe that should be a predeclared identifier next to any and comparable.

Hence import "golang.org/x/exp/constraints" instead of import "constraints".

答案2

得分: 1

你对Map的定义有些不完整。通常声明它的方式应该包含mapper方法。

你的示例可以至少这样实现:

package main

import "fmt"

// Interface to specify something that can be mapped.
type Mappable interface {
}

func main() {
    list_1 := []int{1, 2, 3, 4}
    list_2 := []string{"a", "b", "c", "d"}
    Map(print, list_1)
    Map(print, list_2)
}

func print(value Mappable) {
    fmt.Print(value)
}

// This function maps every element for all []types of array.
func Map(mapper func(Mappable), list ...Mappable) {
    for _, value := range list {
        mapper(value)
    }
}

它是可以工作的。需要说明的是,它有点不确定类型。因为不,Go语言没有 Hindley-Milner 类型系统中的“泛型”功能。

英文:

Your definition of Map is some unсomplete. Usual way to declare it would have mapper method.
Your example can be implemented at least this way

package main

import "fmt"

// Interface to specify something thet can be mapped.
type Mapable interface {
}


func main() {
    list_1 := []int{1, 2, 3, 4}
    list_2 := []string{"a", "b", "c", "d"}
    Map(print, list_1)
    Map(print, list_2)
}
func print(value Mapable){
fmt.Print(value)
}

// This function maps the every element for
// all []types of array.
func Map(mapper func(Mapable), list ... Mapable) {
    for _, value := range list {
        mapper(value)
    }
}

It works. Need to say it's a bit of untyped. Because no, Go has not 'generics' in Hindley-Milner sence

huangapple
  • 本文由 发表于 2014年12月26日 06:11:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/27651119.html
匿名

发表评论

匿名网友

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

确定