Modern Go Idiom for Replacing `for i := 0; i < n; i++` Loops
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 (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:
// 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 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: Contains the formalrange_over_intguideline definition, including the canonical example demonstrating the replacement pattern.README.md: Provides high-level overview documentation referencing the modern looping recommendations.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 nas the modern replacement forfor 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_intin 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →