Exploring the New Features in Go 1.23: Iterators and Enhancements to the Slices & Maps Packages
In a previous post we introduced iterators, a new feature in the Go language added in Go 1.23. In this blog post, we will look into the enhancements made to the slices and maps packages. These changes are built on top of iterators, so would not be possible before this release.
If you’d like to learn more about iterators, you can read our post on it here.
Slice Package
The slices
package adds several functions that work with iterators:
All
All returns an iterator over slice indexes and values.
package main
import (
"fmt"
"slices"
)
func main() {
s := []string{"bytesize", "go", "dot", "com"}
for i, v := range slices.All(s) {
fmt.Printf("%d:%v ", i, v)
}
}
Values
Values returns an iterator over slice elements.
package main
import (
"fmt"
"slices"
)
func main() {
s := []string{"bytesize", "go", "dot", "com"}
for v := range slices.Values(s) {
fmt.Printf("%v ", v)
}
}
Backward
Backward returns an iterator that loops over a slice backward.
package main
import (
"fmt"
"slices"
)
func main() {
s := []string{"bytesize", "go", "dot", "com"}
for i, v := range slices.Backward(s) {
fmt.Printf("%d:%v ", i, v)
}
}
Collect
Collect collects values from an iterator into a new slice.
package main
import (
"fmt"
"slices"
)
func main() {
s := []string{"bytesize", "go", "dot", "com"}
s1 := slices.Collect(slices.Values(s))
fmt.Println(s1)
}
AppendSeq
AppendSeq appends values from an iterator to an existing slice.
package main
import (
"fmt"
"slices"
)
func main() {
s := []string{"bytesize", "go", "dot", "com"}
t := []string{"the", "best", "go", "content"}
u := slices.AppendSeq(s, slices.Values(t))
fmt.Println(u)
}
Sorted
Sorted collects values from an iterator into a new slice, and then sorts the slice.
package main
import (
"fmt"
"slices"
)
func main() {
s := []string{"bytesize", "go", "dot", "com"}
u := slices.Sorted(slices.Values(s))
fmt.Println(u)
}
SortedFunc
SortedFunc is like Sorted
but with a comparison function.
package main
import (
"cmp"
"fmt"
"slices"
)
func main() {
type course struct {
name string
rating int
}
s1 := []course{{"debug", 98}, {"cli", 99}, {"grpc", 100}}
compare := func(c1, c2 course) int {
return cmp.Compare(c1.rating, c2.rating)
}
s2 := slices.SortedFunc(slices.Values(s1), compare)
fmt.Println(s2)
}
SortedStableFunc
SortedStableFunc is like SortFunc
but uses a stable sort algorithm.
package main
import (
"cmp"
"fmt"
"slices"
)
func main() {
type course struct {
name string
rating int
}
s1 := []course{{"debug", 98}, {"cli", 99}, {"grpc", 100}}
compare := func(c1, c2 course) int {
return cmp.Compare(c1.rating, c2.rating)
}
s2 := slices.SortedStableFunc(slices.Values(s1), compare)
fmt.Println(s2)
}
Chunk
Chunk returns an iterator over consecutive sub-slices of up to n elements of a slice.
package main
import (
"fmt"
"slices"
)
func main() {
type course struct {
name string
rating int
}
s1 := []course{{"debug", 98}, {"cli", 99}, {"grpc", 100}}
chunked := slices.Chunk(s1, 1)
for v := range chunked {
fmt.Printf("%v ", v)
}
}
Maps Package
The maps
package adds several functions that work with iterators too!
All
All returns an iterator over key-value pairs from a map.
package main
import (
"fmt"
"maps"
)
func main() {
m := map[string]int{"bytesize": 1, "go": 2, "dot": 3, "com": 4}
for k, v := range maps.All(m) {
fmt.Printf("%v:%v ", k, v)
}
}
Keys
Keys returns an iterator over keys in a map.
package main
import (
"fmt"
"maps"
)
func main() {
m := map[string]int{"bytesize": 1, "go": 2, "dot": 3, "com": 4}
for k := range maps.Keys(m) {
fmt.Printf("%v ", k)
}
}
Values
Values returns an iterator over values in a map.
package main
import (
"fmt"
"maps"
)
func main() {
m := map[string]int{"bytesize": 1, "go": 2, "dot": 3, "com": 4}
for v := range maps.Values(m) {
fmt.Printf("%v ", v)
}
}
Insert
Insert adds the key-value pairs from an iterator to an existing map.
package main
import (
"fmt"
"maps"
)
func main() {
m := map[string]int{"bytesize": 1, "go": 2}
newItems := map[string]int{"dot": 3, "com": 4}
maps.Insert(m, maps.All(newItems))
fmt.Println(m)
}
Collect
Collect collects key-value pairs from an iterator into a new map and returns it.
package main
import (
"fmt"
"maps"
)
func main() {
newItems := map[string]int{"dot": 3, "com": 4}
m := maps.Collect(maps.All(newItems))
fmt.Println(m)
}
Conclusion
Go 1.23’s enhancements to the slices
and maps
packages, alongside the new iter
package, bring a new level of flexibility to data handling in Go. While iterators add a layer of complexity, they also provide a way to write cleaner, more efficient code when dealing with collections.
These updates allow Go developers to handle collections in ways previously unavailable in the language, especially when it comes to generating sequences of values and working with data iteratively. As these features get more widely used, we’ll see if they become a staple in Go development or if they are only used in niche scenarios.
To learn more about all the new features in Go 1.23, check out our course Go 1.23 in 23 minutes.