Categories
golang

go1.18 Generics

The long awaited day of generics in go has finally come. As I’ve been writing go code for years without the need for generics, it is unluckily that generics will be part of the every day programming. In the early days we will see a lot of libraries and examples pop-up for them, but many of them may not be needed as most general use cases will probably be added into the standard library in future release of go. This example is a learning exercise to understand and use generics.

https://go.dev/doc/tutorial/generics – Official Tutorial from go team

Generic Min and Max functions

I’ve always been bothered by the need to cast an integer into a float and back again with working with the math.Min and math.Max functions.

Declaring the type constraint

The constraint tells our generic function what values or behaviors are allowed. We have a list of the some basic constraints already defined in https://pkg.go.dev/golang.org/x/exp that we can take advantage of.

  • Download the constraints package for use go get golang.org/x/exp
type Number interface {
	constraints.Integer | constraints.Float
}

// alternatively without the constraints package we could have
type Numbers interface {
	~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | ~float32 | ~float64
}

Defining generic functions

A generic function looks the same except for the type constraint declared after the function name and before the parameter list `[N Number]. The first parameter is the type name we can use to reference our generic type in the function, the second is the constraint interface we defined above. Multiple constraints can be defined with by a comma separated list.

func Min[N Number](x, y N) N {
	if x < y {
		return x
	}
	return y
}

func Max[N Number](x, y N) N {
	if x > y {
		return x
	}
	return y
}

Use the methods

Hooray, we can now use the Min and Max functions without type casting

func main() {
	fmt.Println("Min int:", Min(1, 5))
	fmt.Println("Min float:", Min(12.5, 5.7))

	fmt.Println("Max int:", Max(1, 5))
	fmt.Println("Min float:", Max(12.5, 5.7))
}

Limitations

The go compile still enforces types with generics we can’t mix different types within a generic function. The return values will be the same type as used in the generic types.

// mixing floats and ints 
Min(1,10.4) // compile error 
Min(float64(1), 10.4)

// missing different int types 
Max(int8(1), int16(5)) // compile error 

var i int 
i = Max(12.5,7.55) // compile error can't set float to int

Leave a Reply

Your email address will not be published.