rss linkedin linkedin gitlab github twitter mastodon instagram
What is new in Go 1.18?
Mar 17, 2022

Disclaimer: This post includes Amazon affiliate links. If you click on one of them and you make a purchase I’ll earn a commission. Please notice your final price is not affected at all by using those links.

Perhaps one of the most anticipated Go releases is here! Superseding Go 1.17, this is Go 1.18, released on March 15, 2022! 💥 🎉 🎊


What is new?

There are lot of brand new language features, in this post I will discuss those I believe are the most relevant and the ones that change the way we use Go.



Updating

Depending on your development platform and the production system you use for running your service you may already have access to start using Go 1.18, however as usual downloading Go is available via the official page.

For more concrete examples:

Type Parameters aka Generics

The code used for this post is available on Github.

Using Types Parameters allows us to implement code that consists of data and behavior where types are not explicitly indicated, the simplest example would be defining a sorting algorithm where it can support any numeric type. For example starting with something like:

 6func Sum(n ...int64) int64 {
 7	var s int64
 8	for _, v := range m {
 9		s += v
10	}
11	return s
12}
13
14func main() {
15	fmt.Println(Sum([]int64{1, 2, 3, 4}...))
16	fmt.Println(Sum(1, 2, 3))
17}

We can rewrite it in such a way it can accept more numeric types, in this case floats and integers:

 9func Sum[V constraints.Float | constraints.Integer](m ...V) V {
10	var s V
11	for _, v := range m {
12		s += v
13	}
14	return s
15}
16
17func main() {
18	fmt.Println(Sum([]int64{1, 2, 3, 4}...))
19	fmt.Println(Sum(1, 2, 3))
20	fmt.Println(Sum(uint32(1), uint32(3)))
21	fmt.Println(Sum(1.2, 2.3, 3.5, 4.6))
22}

Fuzz Test Support

Another testing option that allows us to introduce inputs to our tests in order to find vulnerabilities or inputs that cause crashes, this requires a full blog post to cover the new feature properly, in the meantime I encourage you to read the official documentation, it’s well explained there.

Multi-Modules Workspaces

It’s a mode to allow working with multiple go modules at the same time, this is useful if you happen to be working on multiple Go modules at the same time, this is another feature that requires a dedicated blog post, in the meantime please refer to the official documentation.

Go version included in binary

The code used for this post is available on Github.

This is a change added to the compiler that allows the binary to include VCS information when building the binary, in order to take advantage of that we must use the full module name when building the binary, for example:

go build -o main github.com/MarioCarrion/videos/2022/03/17/002-versions

Next to request version defined in the binary we could either use the debug/buildinfo package or use the command directly like so:

go version -m <binary>

If the binary is compiled using Go 1.18 the output will be similar to:

main: go1.18
	path	github.com/MarioCarrion/videos/2022/03/17/002-versions
	mod	github.com/MarioCarrion/videos/2022/03/17/002-versions	(devel)
	build	-compiler=gc
	build	CGO_ENABLED=1
	build	CGO_CFLAGS=
	build	CGO_CPPFLAGS=
	build	CGO_CXXFLAGS=
	build	CGO_LDFLAGS=
	build	GOARCH=amd64
	build	GOOS=darwin
	build	GOAMD64=v1
	build	vcs=git
	build	vcs.revision=71f09cdcbcd5379cf695a775680597abc2432991
	build	vcs.time=2022-03-17T03:06:39Z
	build	vcs.modified=false

Which happens to include all VCS values as well as the flags used to build the binary, if we recompile the binary using Go 1.17, and the run the same command the output looks like this:

main: go1.17
	path	github.com/MarioCarrion/videos/2022/03/17/002-versions
	mod	github.com/MarioCarrion/videos/2022/03/17/002-versions	(devel)

Quite a big difference.

New net/netip package

The code used for this post is available on Github.

This new package defines a new implementation of the IP type that takes less memory, is immutable, and is comparable so it supports == and can be used as a map key, a concrete example looks like:

 1package main
 2
 3import (
 4	"fmt"
 5
 6	"net"
 7	"net/netip"
 8)
 9
10func main() {
11	ip := "192.168.0.1"
12
13	fmt.Println(net.ParseIP(ip))
14
15	addr, _ := netip.ParseAddr(ip)
16	fmt.Println(addr)
17}

strings includes a new “Cut” function

The code used for this post is available on Github.

strings.Cut in a simplifies other existing functions such as Index, IndexByte, IndexRune and SplintN; also strings.Title was deprecated and replaced by golang.org/x/text/cases. An example of this new function looks like this:

 1package main
 2
 3import (
 4	"fmt"
 5	"strings"
 6)
 7
 8// It can replace and simplify many common uses of Index, IndexByte, IndexRune, and SplitN.
 9
10func main() {
11	cut := func(sep string) {
12		s := "hello|world"
13		before, after, found := strings.Cut(s, sep)
14		fmt.Printf("cut(%q, %q): %q, %q, %v\n", s, sep, before, after, found)
15	}
16
17	cut("|")
18	cut("hello")
19	cut("nothing")
20}

Conclusion

Those are the new features I found interesting, I’m pretty sure Go 1.19 will be exciting as this one, when the time comes I will blog about it for sure.

If you’re looking to sink your teeth into more Go-related topics I recommend the following books:


Back to posts