Skip to main content

Golang-1.21

2023

Golang Release 1.21: slices - Part 2

·2301 words·11 mins· loading · loading
With the release of Go 1.21, the Go standard library introduced several new features. While we’ve already discussed some of them in previous articles, in this episode, we’ll dive into more advanced enhancements. Naturally, we’ll focus on the new functions designed for sorting slices, which are part of the new slices package. This article will provide a deeper look into the implementation of these three new functions and touch on benchmarking as well. Sort # The Sort function is the first one we’d like to explore. This implementation is built upon the enhanced Pattern-defeating Quicksort, positioning it as one of the best-known unstable sorting algorithms. Don’t worry; we will discuss this “instability” aspect in this article. But first, let’s take a look at the function’s signature: Sort function func Sort[S ~[]E, E cmp.Ordered](x S) As we’ve seen in some other articles, nearly all improvements in the Go standard library are built upon generics, a feature introduced in Go version 1.18, almost three years ago. Similar to other functions, the Sort function also expects a slice of a generic type as an argument, where each item must adhere to the Ordered constraint. The function doesn’t return a new value but sorts the original slice in place. Below, you’ll find some basic examples: Sort function examples ints := []int{1, 2, 3, 5, 5, 7, 9} slices.Sort(ints) fmt.Println(ints) // Output: // 1 2 3 5 5 7 9 ints2 := []int{9, 7, 5, 5, 3, 2, 1} slices.Sort(ints2) fmt.Println(ints2) // Output: // 1 2 3 5 5 7 9 floats := []float64{9, 3, 5, 7, 1, 2, 5} slices.Sort(floats) fmt.Println(floats) // Output: // 1 2 3 5 5 7 9 strings := []string{"3", "9", "2", "5", "1", "7", "5"} slices.Sort(strings) fmt.Println(strings) // Output: // 1 2 3 5 5 7 9 In the example above, we can observe the result of the Sort method. All the outputs consist of sorted slices, arranged in ascending order. However, what makes this function particularly intriguing is its ability to handle various data types using a single function, distinguishing it from the implementations we already possess in the sort package. Now that we’ve examined the results, let’s proceed to compare the performance benchmarks with the existing package. Benchmark # In this section, we aim to evaluate the performance of the new function by comparing it to the already existing sort package. Below, you’ll find the benchmark test results:

Golang Release 1.21: slices - Part 1

·1939 words·10 mins· loading · loading
As part of the new Go release, several exciting changes have been introduced to the Go ecosystem. While we’ve explored some of these changes in other articles about the maps package and the cmp package, there’s much more to discover beyond these two packages. In this article, we’ll focus on the first part of the slices package, specifically its new search functionality. Like many other updates and newly introduced packages, this one is also built upon the foundation of generics, which were introduced in Go 1.18. BinarySearch and BinarySearchFunc # Let’s start by exploring the first pair of functions designed for efficiently searching a target value within sorted slices. In this context, we’re referring to the well-known Binary Search algorithm, which is renowned as one of the most significant algorithms and is frequently used in coding interviews. Below, you’ll find the signatures of both of these functions: BinarySearch function func BinarySearch[S ~[]E, E cmp.Ordered](x S, target E) (int, bool) BinarySearchFunc function func BinarySearchFunc[S ~[]E, E, T any](x S, target T, cmp func(E, T) int) (int, bool) Looking at the signatures of both functions, we can identify some small differences between them, and these differences serve specific purposes. The first function, BinarySearch, expects two arguments. The first argument should be a slice of sorted items, and it must adhere to the Ordered constraint. When the items are ordered, the algorithm can efficiently compare them using the Compare function from the cmp package. On the other hand, the second function, BinarySearchFunc, is more versatile. It allows searching within slices where the items don’t necessarily conform to the Ordered constraint. This flexibility is achieved by introducing a third argument, the comparison function. This function is responsible for comparing items and determining their order. It will be called by the BinarySearchFunc itself to make comparisons. Both functions return two values. The first value is the index of the item within the slice, and the second is a boolean value indicating whether the item was found in the slice or not. Let’s explore some examples below: BinarySearch examples fmt.Println(slices.BinarySearch([]int{1, 3, 5, 6, 7}, 5)) // Output: // 2 true fmt.Println(slices.BinarySearch([]int{1, 3, 5, 6, 7}, 9)) // Output: // 5 false fmt.Println(slices.BinarySearch([]int{1, 3, 5, 6, 7}, -5)) // Output: // 0 false fmt.Println(slices.BinarySearch([]string{"1", "3", "5", "6", "7"}, "5")) // Output: // 2 true fmt.Println(slices.BinarySearch([]string{"1", "3", "5", "6", "7", "8"}, "9")) // Output: // 6 false fmt.Println(slices.BinarySearch([]string{"1", "3", "5", "6", "7"}, "4")) // Output: // 2 false Take a close look at the results returned by the BinarySearch function, especially when the item doesn’t exist in the slice. In our examples, we encountered four such cases where the function returned 0, 2, 5, and 6. When the requested item isn’t present in the slice, the function indicates where it should be positioned if it were to be added to the slice. Since the slice is sorted, it’s possible to determine the appropriate position for the item within the slice.

Golang Release 1.21: cmp

·789 words·4 mins· loading · loading
As the new release of Go came this summer, many of us started to look for the improvements inside its ecosystem. Many new features were introduced, including updates to the tool command to support backward and forward compatibility. New packages appeared inside the Standard Library, including maps and slices. In this article we are covering improvements introduced with the new cmp package. The new package offers three new functions. All of them rely on Generics, a feature introduced in Go version 1.18, which has opened up possibilities for many new features. The cmp package introduces new functions for comparing values of Ordered constraint. Let’s dive into each of them. Ordered constraint and Compare function # The constraint Ordered encompasses all types that support comparison operators for values, specifically, <, <=, >= and >. This includes all numeric types in Go, as well as strings. Ordered Constraint type Ordered interface { ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | ~float32 | ~float64 | ~string } Once we understand what the Ordered constraint includes, we can focus on the first function from the cmp package, which is the Compare function. Below, you can find its signature: Compare Function // Compare returns // // -1 if x is less than y, // 0 if x equals y, // +1 if x is greater than y. // ... func Compare[T Ordered](x, y T) int The signature, along with the function description, makes it much easier to understand. The Compare function expects two arguments of the same type, compares their values, and returns a result that represents the comparison status: -1 if the first argument is less than the second. 0 if the arguments’ values are equal. 1 if the first argument is greater than the second. Let’s prove such claim: Compare numerals fmt.Println(cmp.Compare(1, 2)) // Output: // -1 fmt.Println(cmp.Compare(1, 1)) // Output: // 0 fmt.Println(cmp.Compare(2, 1)) // Output: // 1 Compare strings fmt.Println(cmp.Compare("abc", "def")) // Output: // -1 fmt.Println(cmp.Compare("qwe", "qwe")) // Output: // 0 fmt.Println(cmp.Compare("abcde", "abcc")) // Output: // 1 Above, we can see practical examples of the Compare function for both numerals and strings. Indeed, the return values can only belong to the set of numbers {-1, 0, 1}, as defined in the description. Function Less # In addition to the function Compare, we got another, similar function Less. Although it’s rather easy to understand what is used for, let’s check its signature:

Golang Release 1.21: maps

·1573 words·8 mins· loading · loading
Not too long ago, we witnessed a new release of our favorite programming language. The Go team didn’t disappoint us once again. They introduced numerous new features, including updates to the tool command to support backward and forward compatibility. As always, the standard library has received new updates, and the first one we’ll explore in this article is the new maps package. The new package offers only five new functions (two additional ones were removed from the package: Values and Keys), but they provide significant value. All of them rely on Generics, a feature introduced in Go version 1.18, which has opened up possibilities for many new features. The map package clearly provides new tools for Go maps. In this particular case, it introduces new functions for checking map equality, deleting items from maps, copying items into maps, and cloning maps. Let’s dive into each of them. Equal and EqualFunc # First, let’s examine the pair of functions used to check map equality: Equal and EqualFunc. The first one is a straightforward function that checks the equality of two provided maps as function arguments. The second one allows you to pass an additional argument that defines how you plan to examine the equality of values inside the maps. Here are their signatures: Function Equal func Equal[M1, M2 ~map[K]V, K, V comparable](m1 M1, m2 M2) bool Function EqualFunc func EqualFunc[M1 ~map[K]V1, M2 ~map[K]V2, K comparable, V1, V2 any](m1 M1, m2 M2, eq func(V1, V2) bool) bool The Equal function is easier to understand. It simply defines two generic types, M1 and M2, which represent maps of two other generic types, K and V. Obviously, K is for map keys, and it allows any comparable value. The second type is V, representing map values, and it also allows being of a comparable type. The EqualFunc function is slightly more complicated. First, it doesn’t assume that the values in the maps are of the same type, nor do they have to be comparable. For that reason, it introduces an additional argument, which is an equality function for the values in the maps. This way, we can compare two maps that have the same keys but not the same values, and we can define the logic for comparing if they are equal. Simple usage of Equal function first := map[string]string{ "key1": "value1", } second := map[string]string{ "key1": "value1", } fmt.Println(maps.Equal(first, second)) // Output: // true third := map[string]string{ "key1": "value1", } fourth := map[string]string{ "key1": "wrong", } fmt.Println(maps.Equal(third, fourth)) // Output: // false In the example above, there are no surprises. We use four maps to test the Equal function. In the first case, two maps are equal, but in the second case, their values are not the same. The following example is also easy.