Go generics released
Today a first official beta version of go 1.18 was released, which introduces generics to the Go language. This is the most significant change to the language since the release of Go 1. However, it is a backwards compatible change, meaning old code should compile without changes.
Before the release of the 1.18 beta version, you had to compile the go compiler from source in order to experiment with generics. That’s now easier, just download the new version here, look in the “unstable” section.
Other notable features go the upcoming go 1.18 release include
- fuzzing-based-tests for automated fuzzy-tests
- workspaces - which easily let you work with local copies of go modules instead
of using
replace
ingo.mod
(and then accidentally committing it …) any
as a type alias forinterface{}
Say hello to generics
How do go generics look like in go? Let’s start with a simple function, that accepts a generic parameter.
func SayHello[T any](who T) {
fmt.Printf("hello, %v!\n", who)
}
T
is the type parameter of the function SayHello
and any
is the type
constraint. The constraint any
permits any type. Type constraints are
interface types.
The SayHello
method can now be called with different types, without the need
to use interface{}
trickery, nice:
SayHello("generics")
SayHello(23)
SayHello(3.14)
SayHello(true)
Go to the go playground for an executable example.
Go uses monomorphisation to instantiate a generic function, i.e. the compiler
will create different versions of the functions. We can check this with
objdump
tool of go:
$ go tool objdump -S hello|grep "TEXT main.SayHello"
TEXT main.SayHello[go.shape.string_0](SB) /home/jandelgado/src/go-generics/hello.go
TEXT main.SayHello[go.shape.int_0](SB) /home/jandelgado/src/go-generics/hello.go
TEXT main.SayHello[go.shape.float64_0](SB) /home/jandelgado/src/go-generics/hello.go
TEXT main.SayHello[go.shape.bool_0](SB) /home/jandelgado/src/go-generics/hello.go
Four versions of the SayHello
function are generated, one for each different
type, which is inferred by the compiler.
Something useful that comes immediately to my mind is implementing map
,
filter
, reduce
etc. functionality with generics, operating on slices or
channels.
Besides generic functions, go supports generic types like structs. This allows us to design generic data types. The syntax is straight forward:
type Node[T any] struct {
val T
left, right *Node[T]
}
func NewNode[T any](val T, left, right *Node[T]) *Node[T] {
return &Node[T]{val, left, right}
}
func Print[T any](node *Node[T]) {
if node == nil {
return
}
fmt.Println(node.val)
Print(node.left)
Print(node.right)
}
Node
models a node of a binary tree, with an data element val
of type T
, which
can be of any type. Go to the playground for a working example.
That’s it for today. There are already tons of tutorials and blog articles on generics out there. Let’s see what the future brings and how we benefit from generics in Go. I’m pleased by the simple design and that generics unobtrusively integrate into the language.