Question

How to Iterate Over a Range of Integers in Go

goloopsintegerrange

Question

In Go, range can iterate over slices, arrays, maps, strings, and channels. Is there a built-in way to iterate directly over a numeric range, similar to this?

for i := range [1..10] {
    fmt.Println(i)
}

Also, does Go have a built-in representation for integer ranges similar to Ruby's Range class, or is there another idiomatic way to work with a sequence of numbers?

Short Answer

By the end of this page, you will understand how Go handles numeric iteration, why range does not work like Ruby ranges, and the idiomatic way to loop through integers using Go's for statement. You will also learn how to build your own integer range values when needed.

Concept

Go does not have a built-in integer range type like Ruby's Range, and range in Go does not mean “generate numbers from start to end.”

In Go, range is used to iterate over existing collections or stream-like values, such as:

  • arrays
  • slices
  • maps
  • strings
  • channels

That means range works over data that already exists. It does not create a sequence of integers for you.

If you want to count from 1 to 10 in Go, the idiomatic solution is a regular for loop:

for i := 1; i <= 10; i++ {
    fmt.Println(i)
}

This matters because Go is intentionally simple. Instead of adding a special numeric range syntax, the language relies on one flexible looping construct: for.

So the key idea is:

  • Use range to iterate over an existing collection.
  • Use for with start, condition, and increment to iterate through numbers.

If you really need a reusable range-like value, you can create a slice of integers yourself or define your own helper function.

Mental Model

Think of Go's range like walking through items that are already placed in a row on a table.

  • A slice: a row of values already exists.
  • A map: a set of key-value pairs already exists.
  • A string: a sequence of characters already exists.

But a numeric interval like 1..10 is not a row of stored values in Go. It is only an idea: “start here and count until there.”

For that, Go expects you to use a for loop, which is like saying:

  1. Start at 1
  2. Keep going while i <= 10
  3. Add 1 each time

So range walks over something that exists, while for can generate a counting process.

Take Quiz

Syntax and Examples

Basic numeric loop

The standard way to iterate over integers in Go is:

for i := 1; i <= 10; i++ {
    fmt.Println(i)
}

This means:

  • initialize i to 1
  • continue while i <= 10
  • increment i after each iteration

Starting from zero

for i := 0; i < 5; i++ {
    fmt.Println(i)
}

Output:

0
1
2
3
4

Using range with a slice instead

If you create a slice first, then you can use range:

numbers := []int{1, 2, 3, 4, 5}

for index, value := range numbers {
    fmt.Println(index, value)
}

Here, range works because numbers is an actual slice.

Creating a helper to build a range-like slice

package main

import "fmt"

func makeRange(start, end int) []int {
    result := make([]int, 0, end-start+1)
    for i := start; i <= end; i++ {
        result = append(result, i)
    }
    return result
}

func main() {
    for _, n := range makeRange(1, 5) {
        fmt.Println(n)
    }
}

This is useful when you specifically want a collection of integers, but for simple counting, a normal for loop is still the better choice.

Step by Step Execution

Consider this code:

for i := 3; i <= 5; i++ {
    fmt.Println(i)
}

Step by step:

  1. i := 3

    • Go creates i and sets it to 3.
  2. i <= 5

    • 3 <= 5 is true, so the loop body runs.
    • fmt.Println(i) prints 3.
  3. i++

    • i becomes 4.
  4. i <= 5

    • 4 <= 5 is true.
    • Print 4.
  5. i++

    • i becomes 5.
  6. i <= 5

    • 5 <= 5 is true.
    • Print 5.
  7. i++

    • i becomes 6.
  8. i <= 5

    • 6 <= 5 is false.
    • The loop stops.

Output:

3
4
5

This shows that a Go numeric loop is explicit: you control the starting value, stopping condition, and increment.

Real World Use Cases

Numeric iteration appears everywhere in Go programs.

Repeating work a fixed number of times

for i := 0; i < 3; i++ {
    fmt.Println("Retrying...")
}

Useful for retry attempts, polling, or repeated tasks.

Processing indexes in a slice

items := []string{"a", "b", "c"}
for i := 0; i < len(items); i++ {
    fmt.Println(i, items[i])
}

Helpful when you need index-based access.

Generating test data

for i := 1; i <= 100; i++ {
    fmt.Println("user", i)
}

Common in scripts, fixtures, and sample data generation.

Pagination and batching

for page := 1; page <= totalPages; page++ {
    fmt.Println("Fetching page", page)
}

Useful in APIs and background jobs.

Time-based counters or simulations

for second := 0; second < 60; second++ {
    // simulate one second
}

Used in games, simulations, and system logic.

Take Quiz

Real Codebase Usage

In real Go codebases, developers usually prefer the simplest tool that matches the job.

Simple counting with for

For numeric loops, a standard for loop is the default choice:

for i := 0; i < maxRetries; i++ {
    err := tryOperation()
    if err == nil {
        break
    }
}

Guarding loop boundaries carefully

Developers often use constants or variables to avoid magic numbers:

const maxWorkers = 5
for i := 0; i < maxWorkers; i++ {
    startWorker(i)
}

Index loops when values must be updated

scores := []int{10, 20, 30}
for i := 0; i < len(scores); i++ {
    scores[i] += 5
}

This is common when you need to modify elements in place.

range when iterating existing data

for _, user := range users {
    fmt.Println(user.Name)
}

This is cleaner than an index-based loop when you only need values.

Helper functions for generated sequences

Some projects create helper functions when a range-like slice improves readability:

func intsBetween(start, end int) []int {
    nums := make([]int, 0, end-start+1)
    for i := start; i <= end; i++ {
        nums = append(nums, i)
    }
    return nums
}

This is more common in tests, utilities, or data generation than in performance-critical paths.

Common Mistakes

Mistake 1: Expecting range to generate numbers

Broken idea:

for i := range [1..10] {
    fmt.Println(i)
}

Why it is wrong:

  • Go has no 1..10 syntax.
  • range does not generate integer sequences.

Use this instead:

for i := 1; i <= 10; i++ {
    fmt.Println(i)
}

Mistake 2: Off-by-one errors

Broken code:

for i := 1; i < 10; i++ {
    fmt.Println(i)
}

This prints 1 through 9, not 10.

Correct version:

for i := 1; i <= 10; i++ {
    fmt.Println(i)
}

Mistake 3: Using range when you only need a count

Less direct approach:

nums := []int{0, 1, 2, 3, 4}
for i := range nums {
    fmt.Println(i)
}

This works, but only because a slice already exists. If you just want to count, a normal for loop is clearer.

Mistake 4: Confusing index and value in range

Broken expectation:

nums := []int{10, 20, 30}
for n := range nums {
    fmt.Println(n)
}

This prints indexes, not values:

0
1
2

Correct version:

for _, n := range nums {
    fmt.Println(n)
}

Mistake 5: Building slices unnecessarily

If all you need is to print numbers from 1 to 1,000, creating a slice first adds extra memory use.

Prefer:

for i := 1; i <= 1000; i++ {
    fmt.Println(i)
}

instead of creating a temporary slice unless you truly need the collection.

Comparisons

ConceptWhat it doesBest use case
for i := 1; i <= 10; i++Counts through integersNumeric iteration
for _, v := range sliceIterates over existing slice valuesProcessing collections
for k, v := range mapIterates over map entriesReading maps
for condition {}Repeats while condition stays trueUnknown number of iterations

for vs range

Featureforrange
Generates numbers directlyYesNo
Works on slices and mapsIndirectlyYes
Good for custom step sizesYesNo
Best for countingYesNo
Best for existing collectionsSometimesYes

Go vs Ruby style ranges

Language featureGoRuby
Built-in numeric range syntaxNoYes
Built-in range typeNoYes
Idiomatic counting loopforrange-based iteration or loop constructs

Go chooses explicit loops over special range syntax for integers.

Take Quiz

Cheat Sheet

Numeric loop

for i := 1; i <= 10; i++ {
    fmt.Println(i)
}

Count from zero

for i := 0; i < n; i++ {
    // use i
}

Loop backwards

for i := 10; i >= 1; i-- {
    fmt.Println(i)
}

Custom step size

for i := 0; i <= 10; i += 2 {
    fmt.Println(i)
}

range over slice

nums := []int{10, 20, 30}
for index, value := range nums {
    fmt.Println(index, value)
}

Important rules

  • Go has no built-in 1..10 syntax.
  • Go has no built-in integer range type.
  • Use for for numeric counting.
  • Use range for existing collections.
  • In range, the first value is usually the index or key.
  • Use _ to ignore unwanted values.

Common edge cases

  • i < 10 stops before 10
  • i <= 10 includes 10
  • range on a slice gives indexes and values, not generated integers

FAQ

Why doesn't Go support 1..10 syntax?

Go keeps the language small and explicit. Numeric iteration is handled with for instead of special range syntax.

Can I use range to count from 1 to 10 in Go?

Not directly. range iterates over existing values such as slices, maps, strings, and channels.

Does Go have a built-in Range type like Ruby?

No. If you need a reusable range-like structure, you must build it yourself.

What is the idiomatic way to loop over numbers in Go?

Use a standard for loop:

for i := 1; i <= 10; i++ {
    fmt.Println(i)
}

When should I use range instead of for?

Use range when you already have a collection, such as a slice or map, and want to iterate through its elements.

How do I include the end number in a Go loop?

Use <= instead of <.

Can I create my own integer range helper in Go?

Yes. You can write a function that returns a slice of integers or a custom iterator pattern.

Take Quiz

Mini Project

Description

Build a small Go program that prints a sequence of integers between two values. This demonstrates the idiomatic way to work with numeric ranges in Go without relying on a built-in Range type.

Goal

Create a reusable function that prints or returns integers from a start value to an end value using standard Go loops.

Requirements

  • Write a function that accepts start and end integers.
  • Return a slice containing all integers from start to end, inclusive.
  • Use a for loop to build the result.
  • In main, call the function and print each number.
  • Handle the case where start is greater than end by returning an empty slice.
Take Quiz

Keep learning

Related questions

View more