Home Backend Development Golang Understanding Iterators in Go: A Fun Dive!

Understanding Iterators in Go: A Fun Dive!

Oct 25, 2024 am 02:28 AM

Understanding Iterators in Go: A Fun Dive!

If you're a Go programmer, you've probably heard about iterators many times in Go 1.22, and especially in Go 1.23. But maybe you're still scratching your head, wondering why they're useful or when you should use them. Well, you're in the right place! Let's start by looking at how iterators work in Go and why they can be so useful.

A Simple Transformation: No Iterator Yet

Imagine we have a list of numbers, and we want to double each number. We could do this using a straightforward function like the one below:

package main

import (
    "fmt"
)

func NormalTransform[T1, T2 any](list []T1, transform func(T1) T2) []T2 {
    transformed := make([]T2, len(list))

    for i, t := range list {
        transformed[i] = transform(t)
    }

    return transformed
}

func main() {
    list := []int{1, 2, 3, 4, 5}
    doubleFunc := func(i int) int { return i * 2 }

    for i, num := range NormalTransform(list, doubleFunc) {
        fmt.Println(i, num)
    }
}
Copy after login
Copy after login

Here’s what happens when you run this code:

0 2
1 4
2 6
3 8
4 10
Copy after login
Copy after login

Pretty simple, right? This is a basic generic Go function that takes a list of any type T1, applies a transformation function to each element, and returns a new list with the transformed list of any type T2. Easy to understand if you know Go generics!

But what if I told you there’s another way to handle this—using an iterator?

Enter the Iterator!

Now, let’s take a look at how you might use an iterator for the same transformation:

package main

import (
    "fmt"
)

func IteratorTransform[T1, T2 any](list []T1, transform func(T1) T2) iter.Seq2[int, T2] {
    return func(yield func(int, T2) bool) {
        for i, t := range list {
            if !yield(i, transform(t)) {
                return
            }
        }
    }
}

func main() {
    list := []int{1, 2, 3, 4, 5}
    doubleFunc := func(i int) int { return i * 2 }

    for i, num := range NormalTransform(list, doubleFunc) {
        fmt.Println(i, num)
    }
}
Copy after login

Before running it, you must make sure your Go version is 1.23. The output is exactly the same:

0 2
1 4
2 6
3 8
4 10
Copy after login
Copy after login

But wait, why would we need an iterator here? Isn't that more complicated? Let’s dig into the differences.

Why Use an Iterator?

At first glance, iterators seem a bit over-engineered for something as simple as transforming a list. But when you run benchmarks, you start to see why they’re worth considering!

Let’s benchmark both methods and see how they perform:

package main

import (
    "testing"
)

var (
    transform = func(i int) int { return i * 2 }
    list      = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
)

func BenchmarkNormalTransform(b *testing.B) {
    for i := 0; i < b.N; i++ {
        NormalTransform(list, transform)
    }
}

func BenchmarkIteratorTransform(b *testing.B) {
    for i := 0; i < b.N; i++ {
        IteratorTransform(list, transform)
    }
}
Copy after login

Here’s the initial benchmark result:

BenchmarkNormalTransform-8      41292933                29.49 ns/op
BenchmarkIteratorTransform-8    1000000000               0.3135 ns/op
Copy after login

Whoa! That’s a huge difference! But hold on—there’s a bit of unfairness here. The NormalTransform function returns a fully transformed list, while the IteratorTransform function only sets up the iterator without transforming the list yet.

Let’s make it fair by fully looping through the iterator:

func BenchmarkIteratorTransform(b *testing.B) {
    for i := 0; i < b.N; i++ {
        for range IteratorTransform(list, transform) {
        }
    }
}
Copy after login

Now the results are more reasonable:

BenchmarkNormalTransform-8      40758822                29.16 ns/op
BenchmarkIteratorTransform-8    53967146                22.39 ns/op
Copy after login

Okay, the iterator is a bit faster. Why? Because NormalTransform creates an entire transformed list in memory (on the heap) before returning it, while the iterator does the transformation as you loop through it, saving time and memory.

Read more about Stack and Heap here

The iterator's real magic happens when you don’t need to process the whole list. Let’s benchmark a scenario where we only want to find the number 4 after transforming the list:

func BenchmarkNormalTransform(b *testing.B) {
    for i := 0; i < b.N; i++ {
        for _, num := range NormalTransform(list, transform) {
            if num == 4 {
                break
            }
        }
    }
}

func BenchmarkIteratorTransform(b *testing.B) {
    for i := 0; i < b.N; i++ {
        for _, num := range IteratorTransform(list, transform) {
            if num == 4 {
                break
            }
        }
    }
}
Copy after login

The results speak for themselves:

package main

import (
    "fmt"
)

func NormalTransform[T1, T2 any](list []T1, transform func(T1) T2) []T2 {
    transformed := make([]T2, len(list))

    for i, t := range list {
        transformed[i] = transform(t)
    }

    return transformed
}

func main() {
    list := []int{1, 2, 3, 4, 5}
    doubleFunc := func(i int) int { return i * 2 }

    for i, num := range NormalTransform(list, doubleFunc) {
        fmt.Println(i, num)
    }
}
Copy after login
Copy after login

In this case, the iterator is much faster! Why? Because the iterator doesn’t transform the entire list—it stops as soon as it finds the result you’re looking for. On the other hand, NormalTransform still transforms the entire list, even if we only care about one item.

Conclusion: When to Use Iterators?

So, why use an iterator in Go?

  • Efficiency: Iterators can save both time and memory by not processing the entire list if you don’t need it.
  • Flexibility: They allow you to handle large datasets efficiently, especially when working with streams of data or when you need to stop early. But keep in mind, iterators can be a bit trickier to understand and implement. Use them when you need that extra performance boost, especially in scenarios where you don’t need to work with an entire list upfront.

Iterators: They're fast, flexible, and fun—once you get the hang of them!

The above is the detailed content of Understanding Iterators in Go: A Fun Dive!. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Golang's Purpose: Building Efficient and Scalable Systems Golang's Purpose: Building Efficient and Scalable Systems Apr 09, 2025 pm 05:17 PM

Go language performs well in building efficient and scalable systems. Its advantages include: 1. High performance: compiled into machine code, fast running speed; 2. Concurrent programming: simplify multitasking through goroutines and channels; 3. Simplicity: concise syntax, reducing learning and maintenance costs; 4. Cross-platform: supports cross-platform compilation, easy deployment.

Golang and C  : Concurrency vs. Raw Speed Golang and C : Concurrency vs. Raw Speed Apr 21, 2025 am 12:16 AM

Golang is better than C in concurrency, while C is better than Golang in raw speed. 1) Golang achieves efficient concurrency through goroutine and channel, which is suitable for handling a large number of concurrent tasks. 2)C Through compiler optimization and standard library, it provides high performance close to hardware, suitable for applications that require extreme optimization.

The Performance Race: Golang vs. C The Performance Race: Golang vs. C Apr 16, 2025 am 12:07 AM

Golang and C each have their own advantages in performance competitions: 1) Golang is suitable for high concurrency and rapid development, and 2) C provides higher performance and fine-grained control. The selection should be based on project requirements and team technology stack.

Golang vs. Python: Performance and Scalability Golang vs. Python: Performance and Scalability Apr 19, 2025 am 12:18 AM

Golang is better than Python in terms of performance and scalability. 1) Golang's compilation-type characteristics and efficient concurrency model make it perform well in high concurrency scenarios. 2) Python, as an interpreted language, executes slowly, but can optimize performance through tools such as Cython.

Golang vs. Python: Key Differences and Similarities Golang vs. Python: Key Differences and Similarities Apr 17, 2025 am 12:15 AM

Golang and Python each have their own advantages: Golang is suitable for high performance and concurrent programming, while Python is suitable for data science and web development. Golang is known for its concurrency model and efficient performance, while Python is known for its concise syntax and rich library ecosystem.

C   and Golang: When Performance is Crucial C and Golang: When Performance is Crucial Apr 13, 2025 am 12:11 AM

C is more suitable for scenarios where direct control of hardware resources and high performance optimization is required, while Golang is more suitable for scenarios where rapid development and high concurrency processing are required. 1.C's advantage lies in its close to hardware characteristics and high optimization capabilities, which are suitable for high-performance needs such as game development. 2.Golang's advantage lies in its concise syntax and natural concurrency support, which is suitable for high concurrency service development.

Golang's Impact: Speed, Efficiency, and Simplicity Golang's Impact: Speed, Efficiency, and Simplicity Apr 14, 2025 am 12:11 AM

Goimpactsdevelopmentpositivelythroughspeed,efficiency,andsimplicity.1)Speed:Gocompilesquicklyandrunsefficiently,idealforlargeprojects.2)Efficiency:Itscomprehensivestandardlibraryreducesexternaldependencies,enhancingdevelopmentefficiency.3)Simplicity:

Golang and C  : The Trade-offs in Performance Golang and C : The Trade-offs in Performance Apr 17, 2025 am 12:18 AM

The performance differences between Golang and C are mainly reflected in memory management, compilation optimization and runtime efficiency. 1) Golang's garbage collection mechanism is convenient but may affect performance, 2) C's manual memory management and compiler optimization are more efficient in recursive computing.

See all articles