Unveiling the Exciting Enhancements in Go 1.22: A Developer’s Delight
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
- 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 legacyGOPATH
modego mod init
no longer attempts to import module requirements from configuration files for other vendoring tools (such asGopkg.lock
).go test -cover
now prints coverage summaries for covered packages that do not have their own test files.
- 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:
- References to loop variables
- New warnings for missing values after append
- New warnings for deferring time.Since
- New warnings for mismatched key-value pairs in log/slog calls
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.