Boot.dev Blog » Golang » Range Over Ticker in Go With Immediate First Tick

Range Over Ticker In Go With Immediate First Tick

By Lane Wagner on Apr 30, 2020

Curated backend podcasts, videos and articles. All free.

Want to improve your backend development skills? Subscribe to get a copy of The Boot.dev Beat in your inbox each month. It's a newsletter packed with the best content for new backend devs.

The Go standard library has a really cool type - Ticker. Tickers are used when you want to do something at a regular interval, similar to JavaScript’s setInterval. Here’s an example:

package main

import (
	"fmt"
	"time"
)

func main() {
	ticker := time.NewTicker(time.Second)
	go func() {
		for range ticker.C {
			fmt.Println("Tick")
		}
	}()

	time.Sleep(time.Second * 4)
	ticker.Stop()
	fmt.Println("Ticker stopped")
}

As per the docs, a ticker is a struct that holds a receive-only channel of time.Time objects.

type Ticker struct {
    C <-chan Time // The channel on which the ticks are delivered.
}

In the example at the beginning of the article, you will notice by running the program that the first tick sent over the channel happens after the first interval of time has elapsed. As such, if you are trying to build, for example, a rate limiter, it can be inconvenient because to get the first immediate execution, it would seem your best option is:

func doSomethingWithRateLimit() {
	ticker := time.NewTicker(time.Second)
	doSomething()
	for range ticker.C {
		doSomething()
	}
}

There is in fact a better option!

In Go, a channel can also be iterated over in a normal for-loop, so our solution is to build a for loop that executes automatically on the first iteration, then waits for each subsequent loop.

package main

import (
	"fmt"
	"time"
)

func main() {
	ticker := time.NewTicker(time.Minute)
	for ; true; <-ticker.C {
		fmt.Println("hi")
	}
}

Hopefully this helps keep redundant code out of your projects!

Find a problem with this article?

Report an issue on GitHub