00
:
00
:
00
:
00
Corso SEO AI - Usa SEOEMAIL al checkout per il 30% di sconto

Iteratori in Go

A partire da Go 1.23, il linguaggio supporta gli iteratori come funzionalità nativa. Gli iteratori permettono di definire sequenze personalizzate utilizzabili con il ciclo for range.

Concetto di Iteratore

Un iteratore in Go è una funzione che accetta una funzione di yield come parametro e la chiama per ogni elemento della sequenza:

// iter.Seq[V] è il tipo per iteratori a singolo valore
type Seq[V any] func(yield func(V) bool)

// iter.Seq2[K, V] è il tipo per iteratori con chiave-valore
type Seq2[K, V any] func(yield func(K, V) bool)

Creare un Iteratore Semplice

package main

import "fmt"

// Conta restituisce un iteratore che produce numeri da 0 a n-1
func Conta(n int) func(yield func(int) bool) {
    return func(yield func(int) bool) {
        for i := 0; i < n; i++ {
            if !yield(i) {
                return
            }
        }
    }
}

func main() {
    for v := range Conta(5) {
        fmt.Println(v)
    }
    // Output: 0, 1, 2, 3, 4
}

Iteratore con Chiave-Valore (Seq2)

// Enumera aggiunge un indice a ogni elemento di uno slice
func Enumera[T any](s []T) func(yield func(int, T) bool) {
    return func(yield func(int, T) bool) {
        for i, v := range s {
            if !yield(i, v) {
                return
            }
        }
    }
}

func main() {
    nomi := []string{"Alice", "Bob", "Carlo"}
    for i, nome := range Enumera(nomi) {
        fmt.Printf("%d: %s\n", i, nome)
    }
}

Pacchetto slices con Iteratori

Go 1.23 ha arricchito il pacchetto slices con funzioni che restituiscono iteratori:

import "slices"

numeri := []int{3, 1, 4, 1, 5, 9}

// slices.All restituisce un iteratore indice-valore
for i, v := range slices.All(numeri) {
    fmt.Println(i, v)
}

// slices.Values restituisce un iteratore solo-valore
for v := range slices.Values(numeri) {
    fmt.Println(v)
}

// slices.Backward itera in ordine inverso
for i, v := range slices.Backward(numeri) {
    fmt.Println(i, v)
}

// slices.Sorted ordina e restituisce un iteratore
for v := range slices.Sorted(slices.Values(numeri)) {
    fmt.Println(v)
}

Pacchetto maps con Iteratori

import "maps"

capitali := map[string]string{
    "Italia": "Roma",
    "Francia": "Parigi",
}

// maps.Keys restituisce un iteratore sulle chiavi
for chiave := range maps.Keys(capitali) {
    fmt.Println(chiave)
}

// maps.Values restituisce un iteratore sui valori
for valore := range maps.Values(capitali) {
    fmt.Println(valore)
}

Iteratore Personalizzato: Fibonacci

func Fibonacci(max int) func(yield func(int) bool) {
    return func(yield func(int) bool) {
        a, b := 0, 1
        for a <= max {
            if !yield(a) {
                return
            }
            a, b = b, a+b
        }
    }
}

func main() {
    for n := range Fibonacci(100) {
        fmt.Println(n)
    }
    // 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89
}

Pull Iterator

Il pacchetto iter fornisce anche Pull per trasformare un push iterator in un pull iterator:

import "iter"

next, stop := iter.Pull(Conta(5))
defer stop()

v1, ok := next() // 0, true
v2, ok := next() // 1, true

Conclusione

Gli iteratori di Go 1.23 sono una potente aggiunta al linguaggio che permette di creare sequenze personalizzate composabili e utilizzabili con for range. Combinati con i pacchetti slices, maps e iter, offrono un modo idiomatico e performante per lavorare con collezioni di dati.