Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write func for the generic parameter in golang

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.

like image 927
subhash kumar singh Avatar asked Dec 25 '14 22:12

subhash kumar singh


People also ask

How do you use generic in Go?

In programming, a generic type is a type that can be used in conjunction with multiple other types. Typically in Go, if you want to be able to use two different types for the same variable, you'd need to use either a specific interface, such as io. Reader , or use interface{} , which allows any value to be used.

How do you write functions in Golang?

In Golang, we declare a function using the func keyword. A function has a name, a list of comma-separated input parameters along with their types, the result type(s), and a body. The input parameters and return type(s) are optional for a function. A function can be declared without any input and output.

What is a generic type parameter?

Generic Methods A type parameter, also known as a type variable, is an identifier that specifies a generic type name. The type parameters can be used to declare the return type and act as placeholders for the types of the arguments passed to the generic method, which are known as actual type arguments.

Does Goland support generics?

Go 1.18 has been released and along with it comes long-awaited support for Generics! Generics are the most significant change to the language in years. They add a new dimension to what is otherwise a minimalist type system.


2 Answers

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".

like image 157
VonC Avatar answered Oct 26 '22 08:10

VonC


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

like image 29
Uvelichitel Avatar answered Oct 26 '22 09:10

Uvelichitel