You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4.4 KiB

title layout
Go Generics slides.html

Go Generics

  • Let's talk about Go's Generics.
  • What are they?
  • How do I ue them?
  • When do I use them?

Type Parameters

Starting with version 1.18, Go has added support for generics, also known as type parameters.

  • What's a Type Parameter?

Type parameters enable writing functions that work with multiple types.


Example

Consider the following example:

func Index(xs []string, s string) int {
    for i, x := range xs {
        if x == s {
            return i
        }
    }
    return -1
}

Example (cont)

  • What if we want to work with int(s)?
  • We'd have to write another function!
func Index2(xs []int, s int) int {
    for i, x := range xs {
        if x == s {
            return i
        }
    }
    return -1
}
  • Note the only difference are the types.
  • The core logic is the same!

Code Duplication Sucks 😔

Before Go 1.18:

  • Lots of duplicate code! 😱
  • Custom code generators! 🤔
  • Hard to maintain! 😢

Generic Functions 🥳

Let's rewrite our example go use Type Parameters!

func Index[T comparable](s []T, x T) int {
	for i, v := range s {
		if v == x {
			return i
		}
	}
	return -1
}

Instantiation

  • We can use this new generic Index function:
xs := []int{1, 7, 4, 3}
i := Index[int](xs, 7)
fmt.Println(i) // 1
  • Or we can instantiate a function with a type:
fIndex := Index[float64]
  • And use this like a normal function.
xs := []float64{1.2, 3.4, 5.6, 3.14}
i := fIndex(xs, 5.6)
fmt.Println(i) // 2

Type Parameter Syntax

Type Parameters look like this:

func Foo[comparable T](xs T, s T) int

That is the type parameters are defined in "square brackets" in the form of:

[constraint T1, constraint T2, ...]

Constraints

  • So what are constraints then?
  • Let's have a look at comparable
type comparable interface{ comparable }

comparable is an interface that is implemented by all comparable types (booleans, numbers, strings, pointers, channels, arrays of comparable types, structs whose fields are all comparable types)...


Constraints (cont)

  • So Constraints are interfaces?
  • Yes!

For example:

type comparable interface {
    Integer|Float|~string
}

Another Example

Let's look at another example:

func Min(x, y float64) float64 {
    if x < y {
        return x
    }
    return y
}

Another Example (cont)

We can define this as a generic function:

import "golang.org/x/exp/constraints"

func Min[T constraints.Ordered](x, y T) T {
    if x < y {
        return x
    }
    return y

And call it like this:

x := Min(3, 7)
fmt.Println(x) // 3
  • This is Go's Type Inference at play!
  • The compiler will work out the types for you!

When to use?! 🤔

My advice:

  • Write normal code!
  • It's okay to duplicate code!
  • Rule of three.
  • Generics are powerful, simple to use!
  • But no need to rewrite everything as generics! 🤣

🎬 The End 🎬

  • Type Parameters: functions with multiple types
  • Type Constraints: interfaces of the set of types
  • Type Inference: just write normal code

Playground

package main

import "fmt"

type Integer interface {
	int | int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64
}

type Float interface {
	float32 | float64
}

type Ordered interface {
	Integer | Float | ~string
}

func Min[T Ordered](x, y T) T {
	if x < y {
		return x
	}
	return y
}

func main() {
	fmt.Println(Min(3, 7))     // 3
	fmt.Println(Min(1.2, 3.4)) // 1.2
}