What's new in Golang 1.20

What's new in Golang 1.20

Are you ready for the next big thing in the world of Go programming? Go 1.20 is about to shake things up and take your coding game to the next level! This new release packs a punch with a host of new features and solutions to long-standing issues, making it a perfect blend of the groundbreaking Go 1.18 and the steady improvements of Go 1.19.

Syntax changes

Slice to array conversion

Introducing the ability to convert slices to arrays, a feature that has been highly requested by the community. Before Go 1.20, this was not possible and required complex workarounds. But now, with the simple addition of type conversion, you can easily and efficiently convert slices to arrays. The following, which couldn't compile in previous Go versions, can now compile in Go 1.20

package main

import "fmt"

func main() {
    var sl = []string{"one", "two", "three"}
    var arr = [3]string(sl) 
    fmt.Println(sl)
    fmt.Println(arr)
}

Run on Golang Playground

Output in go 1.20rc3:

Output in go 1.19

That's pretty exciting, right?

unsafe package

Three additional functions SliceData, String, and StringData

The Go programming language has an "unsafe" package that provides low-level operations that can be used to break the rules of the type system. In version Go 1.20, it has introduced three new functions: SliceData, String, and StringData. These functions allow developers to construct and deconstruct slice and string values without depending on their exact representation.

SliceData function: func SliceData(slice []ArbitraryType) *ArbitraryType

The SliceData function takes a slice of any type as an argument and returns a pointer to the underlying array of that slice. If the capacity of the slice is greater than 0, it returns &slice[:1][0]. If the slice is nil, it returns nil, otherwise, it returns a non-nil pointer to an unspecified memory address.

package main

import (
    "fmt"
    "unsafe"
)

func main() {
    // Create a slice of integers
    s := []int{1, 2, 3, 4, 5}
    // Get a pointer to the underlying array of the slice
    ptr := unsafe.SliceData(s)
    // Print the pointer
    fmt.Println("Pointer to underlying array:", ptr)
    // Print the value of the first element in the array using pointer arithmetic
    fmt.Println("First element of the array:", *(*int)(ptr))
}

Run on Golang Playground

The String function:func String(ptr *byte, len IntegerType) string

The String function takes a pointer to a byte and an integer type or an untyped constant as arguments, and returns a string value whose underlying bytes start at the pointer and whose length is the integer. If the length is negative or if the pointer is nil and the length is not zero, it will cause a run-time panic.

package main

import (
    "fmt"
    "unsafe"
)

func main() {
    // Create a byte slice
    bs := []byte{'h', 'e', 'l', 'l', 'o'}
    // Get a pointer to the first byte of the slice
    ptr := &bs[0]
    // Use the String function to create a string from the byte slice
    str := unsafe.String(ptr, len(bs))
    // Print the string
    fmt.Println("String:", str)
}

Run on Golang playground

StringData: func StringData(str string) *byte

The StringData function takes a string as an argument and returns a pointer to the underlying bytes of the string. For an empty string, the return value is unspecified and may be nil.

package main

import (
    "fmt"
    "unsafe"
)

func main() {
    // Create a string
    str := "hello"
    // Get a pointer to the underlying bytes of the string
    ptr := unsafe.StringData(str)
    // Print the pointer
    fmt.Println("Pointer to underlying bytes:", ptr)
    // Print the first byte of the string using pointer arithmetic
    fmt.Println("First byte of the string:", *(*byte)(ptr))
}

Run on Golang Playground

Wrapping of errors

Go 1.20 introduces a game-changing new feature: the Join function. This powerful new addition to the Go language makes handling multiple errors a breeze. Say goodbye to checking for errors at every step, and hello to combining multiple errors into a single, manageable error. The Join function wraps a list of errors, making it easy to handle all of them in one place. Upgrade to Go 1.20 and take control of your errors like never before!

package main

import (
    "errors"
    "log"
)

func main() {
    if err := validate("eliya", "4321"); err != nil {
        log.Fatal(err)
    }
}

func validate(username, password string) (err error) {
    if username != "gopher" {
        err = errors.Join(err, errors.New("incorrect username"))
    }
    if password != "1234" {
        err = errors.Join(err, errors.New("incorrect password"))
    }
    return err
}

Run in Golang Playground

Ports

Go 1.20 is the last release that will support older versions of Windows, macOS and FreeBSD. Specifically, it will run on any release of Windows 7, 8, Server 2008 and Server 2012, macOS 10.13 High Sierra or 10.14 Mojave, and it adds experimental support for FreeBSD on RISC-V. However, from Go 1.21, the minimum requirements will be Windows 10 or Server 2016, macOS 10.15 Catalina or later, and the support for other operating systems is not specified.

Tools

Say goodbye to the $GOROOT/pkg

In Go 1.20, the way standard library packages are handled has changed. The $GOROOT/pkg directory, which previously stored pre-compiled package archives for the standard library, will no longer be utilized. Instead, packages in the standard library will be built on demand and cached in the build cache, similar to how packages outside of GOROOT are handled. This change results in a smaller Go distribution and eliminates the potential for C toolchain skew when using cgo.

Cgo

Starting from Go 1.20, the go command will disable cgo by default if a C toolchain is not present on the system. The go command checks if the CGO_ENABLED environment variable is unset, the CC environment variable is unset, and the default C compiler (clang or gcc) is not found in the path. This change is implemented to improve the portability of Go programs by avoiding unexpected build failures on systems without a C toolchain. However, you can still enable cgo by explicitly setting the CGO_ENABLED environment variable.