Unveiling the Exciting Enhancements in Go 1.22: A Developer’s Delight

Yusef Mohamadi
5 min readJan 10, 2024
Go is getting more powerful :D

New Features that You Should Expect in Go 1.22.

Go 1.22 is scheduled for February 2024, but you can already try out many of its features without leaving your browser. Read on and see!

get rid of sharing of loop variables

for the wrong time, it was a common mistake for new Golang developers that comes from another programming language, it was very surprising why!!!! , the variables declared by a “for” loop were created once and updated by each iteration. This led to common mistakes such as the loop-goroutine one:

// go 1.21
values := []int{1, 2, 3, 4, 5}
for _, val := range values {
go func() {
fmt.Printf("%d ", val)
}()
}


// Result : 5 5 5 5 5

In Go 1.22, each iteration of the loop creates new variables, to avoid accidental sharing bugs:

// go 1.22
values := []int{1, 2, 3, 4, 5}
for _, val := range values {
go func() {
fmt.Printf("%d ", val)
}()
}

// Result: 1 2 3 4 5

The change is backward compatible: the new for-loop semantics only applies if the package being compiled is from a module that declares Go 1.22 or later in go.mod.

One of my favorite ones as an ex-python dev is Range over integers

“For” loops may now range over integers:

for i := range 100 {
fmt.Print(i)
}

See the spec for details.

Go 1.22 includes a preview of a language change that the Go team is considering for a future version of Go: range-over-function iterators. Building with GOEXPERIMENT=rangefunc enables this feature.

New math/rand/v2 package

Go 1.22 includes the first “v2” package in the standard library, math/rand/v2. The changes compared to math/rand are detailed in proposal #61716. The Go team plans to include an API migration tool in a future release, likely Go 1.23.

The most important changes are:

No Read method

The Read method, deprecated in math/rand, was not carried forward for math/rand/v2 (it remains available in math/rand). The vast majority of calls to Read should use crypto/rand's Read instead:

package main

import (
"crypto/rand"
"fmt"
)

func main() {
b := make([]byte, 5)
_, err := rand.Read(b)
if err != nil {
panic(err)
}
fmt.Printf("5 random bytes: %v\n", b)
}

Otherwise a custom Read can be constructed using the Uint64 method:

package main

import (
"fmt"
"math/rand/v2"
)

func Read(p []byte) (n int, err error) {
for i := 0; i < len(p); {
val := rand.Uint64()
for j := 0; j < 8 && i < len(p); j++ {
p[i] = byte(val & 0xff)
val >>= 8
i++
}
}
return len(p), nil
}

func main() {
b := make([]byte, 5)
Read(b)
fmt.Printf("5 random bytes: %v\n", b)
}

Generic N-function

The new generic function N is like Int64N or Uint64N but works for any integer type:

{
// random integer
var max int = 100
n := rand.N(max)
fmt.Println("integer n =", n)
}

{
// random unsigned integer
var max uint = 100
n := rand.N(max)
fmt.Println("unsigned int n =", n)
}

Works for durations too (since time.Duration is based on int64):

// random duration
max := 100*time.Millisecond
n := rand.N(max)
fmt.Println("duration n =", n)

Enhanced routing patterns

that I previously wrote about it here.

Trivial but interesting some functions of Slices

The new function Concat concatenates multiple slices:

s1 := []int{1, 2}
s2 := []int{3, 4}
s3 := []int{5, 6}
res := slices.Concat(s1, s2, s3)
fmt.Println(res)

Functions that shrink the size of a slice (Delete, DeleteFunc, Compact, CompactFunc, and Replace) now zero the elements between the new length and the old length (see proposal #63393 for the reasoning).

The old behavior (note the src value after Delete):

// go 1.21
src := []int{11, 12, 13, 14}
// delete #1 and #2
mod := slices.Delete(src, 1, 3)
fmt.Println("src:", src)
fmt.Println("mod:", mod)

New behavior:

// go 1.22
src := []int{11, 12, 13, 14}
// delete #1 and #2
mod := slices.Delete(src, 1, 3)
fmt.Println("src:", src)
fmt.Println("mod:", mod)

Compact example:

src := []int{11, 12, 12, 12, 15}
mod := slices.Compact(src)
fmt.Println("src:", src)
fmt.Println("mod:", mod)

And more

The global generator accessed by top-level functions is unconditionally randomly seeded. Because the API guarantees no fixed sequence of results, optimizations like per-thread random generator states are now possible.

Many methods now use faster algorithms that were not possible to adopt in math/rand because they changed the output streams.

The Mitchell & Reeds LFSR generator provided by math/rand's Source has been replaced by two more modern pseudo-random generator sources: ChaCha8 and PCG. ChaCha8 is a new, cryptographically strong random number generator roughly similar to PCG in efficiency.

ChaCha8 is the algorithm used for the top-level functions in math/rand/v2. As of Go 1.22, math/rand's top-level functions (when not explicitly seeded) and the Go runtime also use ChaCha8 for randomness.

The Source interface now has a single Uint64 method; there is no Source64 interface.

Other changes

Tools

Go command:

  • Commands in workspaces can now use a vendor directory containing the dependencies of the workspace.
  • go get is no longer supported outside of a module in the legacy GOPATH mode
  • go mod init no longer attempts to import module requirements from configuration files for other vendoring tools (such as Gopkg.lock).
  • go test -cover now prints coverage summaries for covered packages that do not have their own test files.

Trace:

  • The trace tool's web UI has been gently refreshed as part of the work to support the new tracer, resolving several issues and improving the readability of various sub-pages.

Vet:

Runtime

The runtime now keeps type-based garbage collection metadata nearer to each heap object, improving the CPU performance (latency or throughput) of Go programs by 1–3%.

This change also reduces the memory overhead of the majority Go programs by approximately 1% by deduplicating redundant metadata.

Compiler

Profile-guided Optimization (PGO) builds can now de-virtualize a higher proportion of calls than previously possible. Most programs from a representative set of Go programs now see between 2 and 14% improvement from enabling PGO.

Summary:

Go 1.22 emerges as a remarkable release, addressing a long-standing loop variable issue that has plagued many Go developers. This update not only rectifies this oversight but also introduces a host of enhancements that streamline code execution and enhance developer productivity.

A notable addition is the new syntactic sugar for iterating over integers. This feature simplifies and beautifies code, making it more elegant and readable. Moreover, the introduction of a new package for handling random numbers paves the way for more efficient and versatile random number generation.

Pattern-based HTTP routing, a feature eagerly awaited by Go practitioners, has finally arrived in Go 1.22. This enhancement empowers developers to create more expressive and flexible web applications, streamlining the routing process and improving overall code organization.

These significant improvements, along with numerous other enhancements, solidify Go 1.22 as a landmark release that significantly elevates the Go language. With its focus on addressing longstanding issues, introducing powerful new features, and enhancing developer experience, Go 1.22 stands as a testament to the Go team’s dedication to continuous improvement.

--

--