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)
}
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))
}
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)
}
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))
}
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
}
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.