GoLang Generics

Generics in GoLang are used to make something generic, i.e a same function or other data structure works with multiple data types

Let’s understand using example

Generics in Function

  • We have an add function that takes two integer and return an integer
    • func add(a int, b int) int
  • Now if we want to do addition of a float type number, then the above mentioned function will not work. And we would need to create a new same function but just with different data types.
  • This is not a efficient way of doing this.
  • We can use generics which makes the add function for multiple types
    • func add[T int | float32 | float64](a T, b T) T
    • We declare T as a type of int or float32 or float64
  • We can also define the type using interface
// ~ allows to use any type that are alias of "int"
// if "~" is not used than UserId type will not work
type Num interface {
	~int | int32 | int64 | float32 | float64
}

func add[T Num](a T, b T) T {
	return a + b
}

type UserId int

func main() {
	res := add(1.1, 2.1)
	fmt.Println("result is: ", res)


	res1 := add(1, 2)
	fmt.Println("result is: ", res1)


	u1 := UserId(1)
	u2 := UserId(2)
	res2 := add(u1, u2)
	fmt.Println("result is: ", res2)
}
  • ”~” is used to allow any alias of a type
    • here in Num if “~int” is not used that adding the UserId type will result int error.

Generics in Struct

  • We can use the generics in struct to have composite data type in some field
// We can have generics in the struct to have any given data type in struct field

type CustomData interface {
	~int | ~string | ~float32
}


type User[T CustomData] struct {
	Id int
	Name string
	Data T
}

func StructGenerics() {
	// We would need to define which type we will be using
	s1 := User[string]{
		Id: 1,
		Name: "Pranav",
		Data: "12",
	}
	fmt.Println(s1)

	s2 := User[int]{
		Id: 1,
		Name: "Pranav",
		Data: 12,
	}
	fmt.Println(s2)

}

Generics in Map

type CustomMap[T comparable, V int | string] map[T]V

func main() {
	m1 := make(CustomMap[int, string])
	m1[1] = "Hello"
	fmt.Println(m1)
}

Generics in Mapping function

// Make a function that executes the given function and returns the result
// eg: input = [1, 2, 3] output = [2, 4, 6]
// Make it generic so it works on multiple types

func mapValues[T Num](values []T, mapFunc func(T) T) []T {
	var newValues []T
	for _, v := range values {
		newValue := mapFunc(v)
		newValues = append(newValues, newValue)
	}
	return newValues
}

func main() {
	res := mapValues([]int{1, 2, 3}, func(a int) int {
		return a * 2
	})
	fmt.Println(res)

	res1 := mapValues([]float32{1.1, 2.1, 3.1}, func(a float32) float32 {
		return a * 2
	})
	fmt.Println(res1)
}