# Modern Go Idiom for Replacing `for i := 0; i < n; i++` Loops

> Discover the modern Go idiom for replacing for i := 0; i < n; i++ loops with Go 1.22's elegant range syntax. Simplify your code and clarify intent.

- Repository: [JetBrains/go-modern-guidelines](https://github.com/jetbrains/go-modern-guidelines)
- Tags: best-practices
- Published: 2026-08-30

---

**Starting with Go 1.22, the modern idiom is `for i := range n` (or `for i := range len(slice)`), which eliminates the explicit initializer, condition, and post statement while clarifying the intent to iterate over indices.**

The JetBrains/go-modern-guidelines repository documents evolutionary patterns that improve Go code clarity and safety. The **modern Go idiom for replacing `for i := 0; i < n; i++` loops** represents a significant syntactic shift introduced in Go 1.22, allowing developers to range directly over integers instead of writing verbose C-style three-clause loops.

## The Range-Over-Integer Syntax (Go 1.22+)

Go 1.22 introduced the ability to use the `range` keyword with integer values. When you write `for i := range n`, the compiler generates a zero-based loop that iterates from `0` to `n-1`, effectively replacing the traditional initialization, condition, and post statements with a single expression.

According to the `range_over_int` guideline defined in [`internal/guidelines/guidelines.json`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/guidelines/guidelines.json) (lines 30-38), this form is now the recommended approach for simple counting loops.

## Before and After: Code Comparison

Consider iterating over the indices of a slice. The classic approach requires explicit management of the loop variable:

```go
// Pre-Go 1.22: Verbose three-clause loop
for i := 0; i < len(items); i++ {
    process(items[i])
}

```

The modern Go 1.22+ idiom eliminates the boilerplate:

```go
// Go 1.22+: Concise range-over-int
for i := range len(items) {
    process(items[i])
}

```

Both snippets produce identical results. The second version makes it immediately obvious that the loop iterates over the valid indices of `items`.

## Why Use the Modern Idiom?

### Readability and Intent

The **range clause** explicitly signals that you are iterating over a sequence of integers from `0` to `n-1`. When a developer sees `range len(items)`, they instantly understand the loop bounds match the collection size, without mentally parsing three separate expressions.

### Safety and Variable Scoping

The compiler guarantees that the loop variable `i` is correctly scoped for each iteration. This prevents the classic closure capture bug where goroutines created inside a loop unexpectedly share the same loop variable. The modern idiom leverages Go's existing range semantics, ensuring each iteration gets its own copy of the index variable.

### Consistency with Range-Based Iteration

Using `for i := range n` aligns with other range-based patterns like `for i, v := range slice`. This consistency reduces cognitive load when switching between index-based and value-based iteration strategies.

## When to Stick with Classic For Loops

The classic `for i := 0; i < n; i++` syntax remains appropriate when you need:

- **Non-zero starting indices**: `for i := 5; i < n; i++`
- **Custom step sizes**: `for i := 0; i < n; i += 2`
- **Dynamic bounds**: When the limit changes during iteration or depends on complex logic evaluated each cycle

The range-over-int form is specifically designed for the common case of zero-based, single-step iteration over a fixed bound.

## Repository Implementation Details

The JetBrains/go-modern-guidelines repository defines and validates this pattern through several key files:

- **[`internal/guidelines/guidelines.json`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/guidelines/guidelines.json)**: Contains the formal `range_over_int` guideline definition, including the canonical example demonstrating the replacement pattern.
- **[`README.md`](https://github.com/JetBrains/go-modern-guidelines/blob/main/README.md)**: Provides high-level overview documentation referencing the modern looping recommendations.
- **[`internal/guidelines/guidelines_test.go`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/guidelines/guidelines_test.go)**: Houses the test suite ensuring the guideline engine correctly identifies opportunities to apply the range-over-int idiom.

These files collectively enforce the `range_over_int` rule across Go codebases using JetBrains tooling.

## Summary

- Go 1.22 introduced `for i := range n` as the modern replacement for `for i := 0; i < n; i++`
- The idiom eliminates boilerplate while preventing closure variable capture bugs
- Use `for i := range len(slice)` to clearly express index iteration over collections
- Classic three-clause loops remain necessary for non-zero starts, custom steps, or dynamic bounds
- The pattern is formally defined as `range_over_int` in the JetBrains/go-modern-guidelines repository

## Frequently Asked Questions

### When was range over integers introduced in Go?

The `for i := range n` syntax was introduced in **Go 1.22**, released in February 2024. Prior versions require the classic three-clause `for` loop for integer iteration.

### Can I use variables other than `len()` with range over int?

Yes. You can range over any non-negative integer variable or literal, such as `for i := range count` or `for i := range 10`. The integer expression is evaluated once before the loop begins.

### Is the range-over-int idiom backward compatible?

No. Code using `for i := range n` requires Go 1.22 or later. The JetBrains/go-modern-guidelines repository marks this as a Go 1.22+ specific modernization that should only be applied when the module's Go version permits.

### Does the modern idiom perform differently than classic loops?

No. Modern Go compilers optimize both forms to identical machine code. The range-over-int syntax is purely a semantic improvement offering better readability and safety guarantees without runtime overhead.