ZetCode

Golang maps.Keys

last modified May 1, 2026

This tutorial explains how to use the maps.Keys function in Go. We'll cover map operations with practical examples of extracting and processing keys.

The maps.Keys function returns an iterator (specifically an iter.Seq[K]) over the keys in a map. Introduced in the standard maps package in Go 1.23, this replaces earlier experimental versions. Because it returns an iterator, it does not allocate a new slice until you explicitly request one using slices.Collect.

This function is useful when you need to treat the keys as a separate sequence to be passed to other functions, validated, or sorted. As with all map operations in Go, the order of keys yielded by the iterator is not guaranteed.

Note: If you simply need to iterate over keys in a for loop, ranging over the map directly (for k := range myMap) is more efficient and idiomatic than using maps.Keys.

Basic maps.Keys Example

To get a printable list of keys from a map, we use maps.Keys in conjunction with slices.Collect. This converts the sequence of keys into a standard Go slice.

basic_keys.go
package main

import (
    "fmt"
    "maps"
    "slices"
)

func main() {
    fruitPrices := map[string]int{
        "apple":  5,
        "banana": 3,
        "orange": 4,
    }
    
    // We collect the iterator into a slice for display
    keys := slices.Collect(maps.Keys(fruitPrices))
    fmt.Println("Fruit keys:", keys)
}

We create a map of fruit prices and use maps.Keys to obtain the iterator. slices.Collect then builds the slice. The output displays the fruit names in an arbitrary order.

Working with Numeric Keys

maps.Keys handles any valid map key type, including integers. This example demonstrates extracting numeric keys from a status code map.

numeric_keys.go
package main

import (
    "fmt"
    "maps"
    "slices"
)

func main() {
    statusCodes := map[int]string{
        200: "OK",
        404: "Not Found",
        500: "Internal Server Error",
    }
    
    codes := slices.Collect(maps.Keys(statusCodes))
    fmt.Println("HTTP status codes:", codes)
}

The function provides an iterator of integers. Once collected, the resulting slice contains the HTTP status codes.

Empty Map Behavior

When maps.Keys is called on an empty map, it returns an empty iterator. Collecting this yields a nil or empty slice.

empty_map.go
package main

import (
    "fmt"
    "maps"
    "slices"
)

func main() {
    emptyMap := map[string]bool{}
    
    keys := slices.Collect(maps.Keys(emptyMap))
    fmt.Println("Keys from empty map:", keys)
    fmt.Println("Length of keys slice:", len(keys))
}

The output will show an empty slice [] and a length of 0, demonstrating that the function handles empty maps gracefully without crashing.

Using Keys for Iteration

While you can range over maps.Keys, it is usually better to range over the map directly. However, for consistency in pipelines using Go's iter package, you can use it as shown below.

key_iteration.go
package main

import (
    "fmt"
    "maps"
    "strings"
)

func main() {
    userRoles := map[string]string{
        "alice": "admin",
        "bob":   "editor",
        "eve":   "viewer",
    }
    
    // We range over the iterator directly
    for username := range maps.Keys(userRoles) {
        fmt.Println("Processing user:", strings.ToUpper(username))
    }
}

We iterate through the keys sequence and transform each username to uppercase. Note that for username := range userRoles would be functionally identical and slightly more efficient.

Sorting Extracted Keys

Because map iteration is randomized, sorting keys is a very common requirement. We collect the keys into a slice and then use slices.Sort.

sorted_keys.go
package main

import (
    "fmt"
    "maps"
    "slices"
)

func main() {
    countryPopulations := map[string]int{
        "China":  1439,
        "India":  1380,
        "USA":    331,
        "Brazil": 213,
    }
    
    // First, get the keys as a slice
    countries := slices.Collect(maps.Keys(countryPopulations))
    
    // Then, sort the slice in place
    slices.Sort(countries)
    
    fmt.Println("Countries sorted alphabetically:")
    for _, country := range countries {
        fmt.Println(country)
    }
}

By collecting the iterator into a slice, we gain the ability to sort the data. The output will now consistently show the countries in alphabetical order.

Working with Custom Types

Any type that is comparable can serve as a map key. maps.Keys is fully compatible with custom struct keys.

custom_type_keys.go
package main

import (
    "fmt"
    "maps"
    "slices"
)

type Coordinate struct {
    X, Y int
}

func main() {
    gridValues := map[Coordinate]string{
        {1, 1}: "start",
        {2, 3}: "treasure",
        {4, 2}: "enemy",
    }
    
    coordinates := slices.Collect(maps.Keys(gridValues))
    fmt.Println("Map coordinates:", coordinates)
}

We define a Coordinate struct and use it as a key. maps.Keys correctly extracts these structs into an iterator of Coordinate values.

Source

Go maps package documentation

This tutorial covered the maps.Keys function in Go with practical examples of extracting, sorting, and validating map keys using modern iterator patterns.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Go tutorials.