Break out of Nested Loops in Go

How do you break out of nested loops in Go? A simple breaksometimes just won’t do! A common pattern I use is some sort of ticker function, the following doesn’t behave as you might think:

package main

import (
	"fmt"
	"time"
)

func main() {
	stop := make(chan interface{})

	go func() {
		for {
			select {
			case <-time.After(time.Second):
				fmt.Println("tick")
			case <-stop:
				fmt.Println("stopping")
				break
			}
		}
		fmt.Println("stopped")
	}()

	time.Sleep(3 * time.Second)

	stop <- true

	time.Sleep(3 * time.Second)
}

You might expect the output to be along the lines of:

tick
tick
tick
stopping
stopped

WRONG!

Instead you’ll see the following:

tick
tick
tick
stopping
tick
tick
tick

Check it out here.

The break only breaks out of the select, but the for loop continues indefinitely! To break out of the for, we need to use a label, like so:

package main

import (
	"fmt"
	"time"
)

func main() {
	stop := make(chan interface{})

	go func() {
	ForLoop:
		for {
			select {
			case <-time.After(time.Second):
				fmt.Println("tick")
			case <-stop:
				fmt.Println("stopping")
				break ForLoop
			}
		}
		fmt.Println("stopped")
	}()

	time.Sleep(3 * time.Second)

	stop <- true

	time.Sleep(3 * time.Second)
}

The output is now as expected:

tick
tick
tick
stopping
stopped

Try it out here!

Leave a Reply

Your email address will not be published. Required fields are marked *