英文:
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
}
> 我们在标准库中放弃了constraints
,因为我们认为它是使用泛型的基础,但实际上并非如此。
>
> 特别是,大多数代码使用any
或comparable
。
如果这些是唯一的常见约束条件,也许我们不需要该包。
或者如果constraints.Ordered
是唯一的其他常用约束条件,也许它应该是与any
和comparable
并列的预声明标识符。
因此,使用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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论