Daaang Amy
open main menu

Generics in Go

/ 2 min read
Last updated:

Why Generics?

To write DRY code! Generics allows us to use variable to refer to specific types. This helps us reduce code duplication.

How To Use Generics

Define a variable with the constraint any. The variable does not have to be named T.

func yourFunc[T any](s []T) ([]T) {
	// your code here
}

From this example, we’ve defined T to constraint any and use it to define both the argument and return type to []T. Which means a slice of any type.

Constraints

Constraints are interfaces that allow us to write generics that only operate within the constraints of a given interface type. This means that any interface we define could possible be used as a generic constraint. The any constraint is the same as a empty interface which will match anything.

Create Custom Constraints

The concat function takes a slice of values and concatenates it into a string. This should work with any type that can represent itself as a string.

type stringer interface {
    String() string
}

func concat[T stringer](vals []T) string {
    result := ""
    for _, val := range vals {
        // this is where the .String() method
        // is used. That's why we need a more specific
        // constraint instead of the any constraint
        result += val.String()
    }
    return result
}

Interface Type Lists

We can also create interfaces with just a list of types.

type Number interface {
	~int | ~int8 | ~int16 | ~int32 | ~int64 |
	~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | 
	~float32 | ~float64
}

Parametic Constraints

Interface definitions can accept type parameters as well.

type store[P product] interface {
	Sell(P)
}

type product interface {
	Price() float64
	Name() string
}

type guitar struct {
	name string
	manufacturer string
	price float64
}

func (g guitar) Name() string {
	return fmt.Sprintf("%s by %s", b.name, b.manufacturer)
}

func (g guitar) Price() float64 {
	return g.price
}

type guitarStore struct {
	guitarsSold []guitar
}

func (gs *guitarStore) Sell(g guitar) {
	gs.guitarsSold = append(gs.guitarsSold, g)
}