# How the go-modern-guidelines Tool Handles Go 1.22's `range over int` Feature

> Discover how the go-modern-guidelines tool simplifies Go 1.22 range over int syntax, replacing classic loops with concise range loops while preserving traditional loops for complex cases.

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

---

**The JetBrains go-modern-guidelines CLI automatically detects Go 1.22+ environments and recommends replacing classic `for i := 0; i < n; i++` loops with the concise `for i := range n` syntax, while explicitly preserving traditional for-loops for non-zero starts, custom steps, and mutable bounds.**

Go 1.22 introduced the `range over int` feature, allowing zero-based count loops without explicit initialization, condition, or increment statements. The `JetBrains/go-modern-guidelines` repository provides a command-line tool that analyzes your Go version through [`internal/goversion/goversion.go`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/goversion/goversion.go) and applies the `range_over_int` guideline from [`internal/guidelines/guidelines.json`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/guidelines/guidelines.json) to suggest modernizations that reduce boilerplate while maintaining correctness.

## Version Detection and Guideline Activation

The tool determines whether your codebase supports the `range over int` syntax by evaluating the target Go version against the 1.22 threshold. In [`internal/goversion/goversion.go`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/goversion/goversion.go), the `Compare` function checks the current version context to filter which modernization rules apply.

When the detected version is greater than or equal to 1.22, the engine activates the specific guideline defined at lines 630-648 of [`internal/guidelines/guidelines.json`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/guidelines/guidelines.json). This version-gated approach ensures the tool only suggests language features compatible with your toolchain, preventing invalid recommendations in older projects.

## How the Guideline Engine Processes Loop Patterns

The CLI loads and renders recommendations through a pipeline defined in [`internal/guidelines/guidelines.go`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/guidelines/guidelines.go). The `mustLoadModernGoGuidelines` function parses the JSON guideline definitions, including the `range_over_int` rule marked with **Critical** impact, while `writeExamples` (lines 86-100) formats the human-readable output shown during `list` or `explain` commands.

When invoked through [`main.go`](https://github.com/JetBrains/go-modern-guidelines/blob/main/main.go), the tool executes this workflow:

1. **Version Resolution**: Calls `goversion.Compare` to validate Go 1.22+ support.
2. **Guideline Filtering**: Loads applicable rules from [`internal/guidelines/guidelines.json`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/guidelines/guidelines.json).
3. **Pattern Analysis**: Identifies count loops that match the zero-based, single-step criteria.
4. **Rendering**: Generates before/after examples via `writeExamples`, including explicit warnings for exception cases.

## Recognized Loop Patterns and Exceptions

The tool categorizes count loops into transformations and explicit exceptions based on semantic requirements.

### Recommended: Simple Zero-Based Counting

**Bold Transformation**: Loops iterating from 0 to n-1 with a step of 1 should use `for i := range n`.

This pattern eliminates three clauses of boilerplate while preserving identical behavior. The guideline applies when iterating over slice lengths or numeric constants where the index starts at zero and increments uniformly.

### Preserved: Classic For-Loop Exceptions

The tool explicitly rejects `range over int` for three specific scenarios:

- **Non-zero start**: `for i := 5; i < len(items); i++` must remain classic because `range` always initializes at 0.
- **Custom step increments**: `for i := 0; i < n; i += 2` requires traditional syntax since `range` cannot express step values other than 1.
- **Mutable bounds**: Loops where `len(slice)` changes during iteration must use the classic form to re-evaluate the condition each cycle, whereas `range` captures the bound once at initialization.

## Code Transformation Examples

The following patterns demonstrate how the tool differentiates between recommended modernizations and legacy preservation.

### Zero-Based Index with Length (Transform)

```go
// Before: Classic for-loop
for i := 0; i < len(items); i++ {
    process(items[i])
}

// After: Range over int
for i := range len(items) {
    process(items[i])
}

```

### Non-Zero Start Index (Preserve)

```go
// Keep classic form: starts at 5, not 0
for i := 5; i < len(items); i++ {
    process(items[i])
}

```

### Custom Step Increment (Preserve)

```go
// Keep classic form: step size of 2
for i := 0; i < len(items); i += 2 {
    process(items[i])
}

```

### Mutable Bound During Iteration (Preserve)

```go
// Keep classic form: bound changes during iteration
for i := 0; i < len(items); i++ {
    if shouldDrop(i) {
        items = items[:len(items)-1] // mutates length
    }
    process(items[i])
}

```

### Fixed Numeric Range (Transform)

```go
// Transform to range over int
for i := range 10 {
    fmt.Println(i) // prints 0..9
}

```

## Summary

- The `range over int` guideline activates only when `goversion.Compare` in [`internal/goversion/goversion.go`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/goversion/goversion.go) detects Go 1.22 or later.
- Guideline definitions are stored in [`internal/guidelines/guidelines.json`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/guidelines/guidelines.json) (lines 630-648) with **Critical** priority due to significant boilerplate reduction.
- `mustLoadModernGoGuidelines` and `writeExamples` in [`internal/guidelines/guidelines.go`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/guidelines/guidelines.go) (lines 86-100) handle JSON parsing and CLI output formatting.
- The tool recommends `for i := range n` exclusively for zero-based, single-step loops with immutable bounds.
- Classic for-loops must be preserved for non-zero starts, custom increments (e.g., `i += 2`), and scenarios where the iteration bound mutates during execution.

## Frequently Asked Questions

### Can the tool automatically refactor my code, or does it only provide recommendations?

The JetBrains go-modern-guidelines CLI currently operates as a linter and educator rather than an automated refactoring tool. When you run the `list` or `explain` commands, the tool analyzes your Go version via [`internal/goversion/goversion.go`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/goversion/goversion.go) and displays specific guideline details rendered by `writeExamples`. You must manually apply transformations based on these recommendations.

### Why does the tool reject `range over int` for loops that modify the slice length during iteration?

The `range` expression evaluates the bound exactly once at loop initialization. If your code reslices the array or appends to the slice within the loop body, the range uses the stale initial length, potentially causing missed elements or index out-of-bounds errors. The traditional `for i := 0; i < len(s); i++` form re-evaluates `len(s)` on each iteration, making it the only safe choice for mutable-bound loops.

### How does the tool handle Go versions earlier than 1.22?

For projects targeting Go versions below 1.22, the `goversion.Compare` function filters out the `range_over_int` guideline entirely. The guideline record in [`internal/guidelines/guidelines.json`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/guidelines/guidelines.json) specifies the minimum version constraint, so the rendering engine excludes this recommendation from output, preventing the suggestion of unsupported language features in legacy codebases.

### Does the tool support `range` over other integer types like `int64`?

Based on the guideline implementation in [`internal/guidelines/guidelines.json`](https://github.com/JetBrains/go-modern-guidelines/blob/main/internal/guidelines/guidelines.json), the tool specifically targets the standard `int` type used in length expressions like `len(slice)`. While Go 1.22's `range over int` supports any integer type, the tool's pattern recognition focuses on the most common idioms involving `len()` results and explicit integer constants where `int` is the default type.