简体   繁体   English

如何在 Go 中创建泛型方法? (方法必须没有类型参数)

[英]How to create generic method in Go? (method must have no type parameters)

Golang 1.18beta supports generic, I want to add an extension method on a generic slice. Golang 1.18beta 支持泛型,我想在泛型切片上添加扩展方法。 eg a map function is defined as this:例如 map function 被定义为:

func Map[E, V any](slice *[]E, iteratee func(E) V) *[]V {
    result := []V{}
    for _, item := range *slice {
        result = append(result, iteratee(item))
    }

    return &result
}

Then I want to make this method as an extension method of slice, something like this, but cannot compile successfully:然后我想把这个方法做为 slice 的扩展方法,类似这样,但无法编译成功:

func (slice *[]E) Map[E, V any](iteratee func(E) V) *[]V {
    result := []V{}
    for _, item := range *slice {
        result = append(result, iteratee(item))
    }

    return &result
}

go build with Go 1.18 gives the error: go build与 Go 1.18 给出了错误:

main.go: method must have no type parameters

What is the correct way to implement the second code block?实现第二个代码块的正确方法是什么?

I want to use like this:我想这样使用:

slice := []string{"a", "b", "c"}
newSlice := slice.Map(func(s string) string {
        return s + "122"
    })

You have to declare the slice type with type parameters you want to use for the Map() (or for any other) method:您必须使用要用于Map() (或任何其他)方法的类型参数声明slice类型:

type slice[E, V any] []E

And you have to add the type parameters to the receiver, without the constraints (those will be the same as defined at the type declaration), as if you'd instantiate the generic slice type:并且您必须将类型参数添加到接收器,没有约束(这些将与类型声明中定义的相同),就好像您要实例化通用slice类型一样:

func (s *slice[E, V]) Map(iteratee func(E) V) *[]V {
    result := []V{}
    for _, item := range *s {
        result = append(result, iteratee(item))
    }

    return &result
}

Testing it:测试它:

s := slice[int, string]{1, 2, 3}
m := s.Map(func(i int) string { return fmt.Sprint("x", i) })
fmt.Println(m)

Which will output (try it on the Go Playground ):哪个将 output (在Go Playground上尝试):

&[x1 x2 x3]

Also note that slices (slice headers) already contain a pointer to an underlying array, so it's rare that you need to use a pointer to slice.另请注意,切片(切片标头)已经包含指向底层数组的指针,因此您很少需要使用指向切片的指针。 Instead declare the method with non-pointer receiver, and return a non-pointer:而是用非指针接收器声明方法,并返回一个非指针:

func (s slice[E, V]) Map(iteratee func(E) V) []V {
    result := []V{}
    for _, item := range s {
        result = append(result, iteratee(item))
    }

    return result
}

Relevant section from the (tip) spec: Spec: Method declarations: (提示)规范中的相关部分:规范:方法声明:

If the receiver base type is a parameterized type , the receiver specification must declare corresponding type parameters for the method to use.如果接收器基类型是参数化类型,则接收器规范必须声明相应的类型参数以供方法使用。 This makes the receiver type parameters available to the method.这使得接收器类型参数可用于该方法。

Syntactically, this type parameter declaration looks like an instantiation of the receiver base type, except that the type arguments are the type parameters being declared, one for each type parameter of the receiver base type.从语法上讲,这个类型参数声明看起来像是接收器基类型的实例化,除了类型 arguments 是被声明的类型参数,每个接收器基类型的类型参数一个。 The type parameter names do not need to match their corresponding parameter names in the receiver base type definition, and all non-blank parameter names must be unique in the receiver parameter section and the method signature.类型参数名称不需要与接收者基类型定义中对应的参数名称匹配,并且所有非空白参数名称在接收者参数部分和方法签名中必须是唯一的。 The receiver type parameter constraints are implied by the receiver base type definition: corresponding type parameters have corresponding constraints.接收器类型参数约束由接收器基类型定义隐含:对应的类型参数有对应的约束。

Then I want to make this method as an extension method of slice然后我想把这个方法作为 slice 的扩展方法

You can't do this with or without generics.无论有没有 generics,您都无法做到这一点。 You can only define methods on named types, and in your second snippet, E is not a type, it's a type parameter .您只能在命名类型上定义方法,并且在第二个代码段中, E不是类型,它是类型参数

A slice, in itself, in Go isn't a named type, which is a required condition for declaring methods on it. Go 中的切片本身不是命名类型,这是在其上声明方法的必要条件。 Unlike Javascript that has prototypes, a slice type in Go must be a slice of something , ie a defined type, in order to have methods on it.与具有原型的 Javascript 不同,Go 中的切片类型必须是某物的切片,即定义的类型,以便在其上具有方法。 As a matter of fact, it's formally defined in the language specs as:事实上,它在语言规范中正式定义为:

SliceType = "[" "]" ElementType .

So you can't define a method on any and all slices .因此,您不能在任何和所有 slices 上定义方法。 You can declare methods on named slice types, which may then be parametrized.您可以在命名切片类型上声明方法,然后可以对其进行参数化。

But in order to use the second type param V , it must be defined on the type declaration.但是为了使用第二种类型参数V ,它必须在类型声明中定义。 Methods are not permitted to have type params not specified on the receiver type .方法不允许具有未在接收器类型上指定的类型参数 For example:例如:

type Slice[T, V any] []T

func (s Slice[T,V]) Map(iteratee func(T) V) []V {
    result := make([]V, 0)
    for _, item := range s {
        result = append(result, iteratee(item))
    }

    return result
}

But at this point, you might as well keep using a generic function, that has the advantage of permitting type inference, thus allowing you to have less verbose code and omit explicit type params during the instantiation.但此时,您不妨继续使用通用 function,它具有允许类型推断的优势,从而允许您在实例化过程中减少冗长的代码并省略显式类型参数。

Playground showing method vs func: https://gotipplay.golang.org/p/R7uAq0SBUjj游乐场展示方法与功能: https://gotipplay.golang.org/p/R7uAq0SBUjj

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM