Increment and Decrement
Understand how the increment and decrement statements work in Go, why they are not expressions, and how to use them safely in loops and variable updates.
Go provides two built-in statements that change a numeric variable by exactly one: the increment statement (++) and the decrement statement (--). They look familiar if you come from C, Java, or JavaScript, but they behave differently in a way that often surprises newcomers. In Go, ++ and -- are statements, not operators. They do not produce a value, and they cannot appear as part of a larger expression. You write i++ as a command on its own line — never as an argument or inside an assignment.
Why Go Treats Increment and Decrement as Statements
The designers of Go removed the expression form of ++ and -- to eliminate a category of subtle bugs that have plagued C-like languages for decades. In those languages, x = y++ relies on a specific evaluation order and a temporary value. The postfix form means “save the old value, increment the variable, then return the old value.” Prefix ++x means “increment first, then return the new value.”
Mixing these with other operations in the same expression creates side effects that are easy to misread and hard to debug. Consider a C expression like arr[i++] = i. The result depends on unspecified evaluation order — undefined behavior that can silently produce different results on different compilers.
Go’s stance is simple: if you want to increment a variable, say so with a dedicated statement. If you need the old value and an increment, write two lines. No magic, no hidden temporaries, no platform-specific evaluation order. This aligns with the language’s broader philosophy of favoring clarity over cleverness.
No Prefix Form:
Go also removes the prefix ++i and --i entirely. Only the postfix notation i++ and i-- exists. The two forms are not needed because the statement never returns a value. There is no ambiguity to resolve.
How Increment and Decrement Work in Go
An increment or decrement statement is written as a variable name followed by ++ or --. The statement must stand alone; it cannot be combined with any other operator or assigned to anything.
var counter int = 0
counter++ // counter is now 1
counter-- // counter is now 0
Mechanically, counter++ is equivalent to counter += 1, and counter-- is equivalent to counter -= 1. However, the ++ and -- forms are not syntactic sugar for those assignment operations — they are distinct statement types in the language grammar. The compiler checks that they appear only where a statement is allowed, and it rejects any attempt to use them where an expression is expected.
The variable you increment must be addressable (a named variable, a slice or array element, or a map index expression). It must also be of a numeric type: any integer, floating-point, or complex type.
var price float64 = 19.99
price++ // price == 20.99
var flags complex128 = 3 + 4i
flags-- // flags == 2 + 4i
Correct and Predictable:
Each of these lines compiles and does exactly what you expect — the value changes by 1 in place. There is no return value to capture, no expression to evaluate out of order. The statement is self-contained.
Common Beginner Mistakes
The most common mistake by far is trying to use ++ or -- as if they were expressions. This usually comes from habits formed in C-derived languages.
Using Increment Inside Another Statement
The compiler rejects any code that places ++ or -- inside a larger expression.
x := 10
y := x++ // compile error: syntax error: unexpected ++, expected expression
fmt.Println(x++) // compile error: x++ used as value
if x++ > 10 {} // compile error: x++ used as value
Compilation Will Fail:
Go will not compile a program that treats ++ or -- as a value. These are not operators; they cannot be embedded. The fix is always to separate the increment onto its own line.
If you need the old value of x while also incrementing it, you must write two lines:
old := x
x++
fmt.Println(old, x)
Using Prefix Notation
Many newcomers instinctively write ++i inside a for loop.
for i := 0; i < 5; ++i { // compile error: syntax error: unexpected ++, expecting { after for clause
}
The Go for loop’s post statement expects a simple statement, but only the postfix forms i++ and i-- exist. There is no ++i in Go at all. The correction is straightforward:
for i := 0; i < 5; i++ {
fmt.Println(i)
}
Applying to Non‑Numeric or Non‑Variable Operands
The operand must be a numeric variable. Trying to increment a string, a boolean, or a constant will cause a compile error.
const n = 5
n++ // compile error: cannot assign to n (constant 5)
name := "Go"
name++ // compile error: invalid operation: name++ (non-numeric type string)
Only Addressable Numeric Values:
Increment and decrement require a variable that can be modified. Literals, constants, and function return values are not addressable and cannot appear on the left side of ++ or --.
Using Increment and Decrement in Loops
The most frequent real‑world use of i++ and i-- is inside for loops. The post statement of a for clause is exactly where these statements shine.
// Forward iteration
for i := 0; i < len(items); i++ {
fmt.Println(items[i])
}
// Backward iteration with decrement
for i := len(items) - 1; i >= 0; i-- {
fmt.Println(items[i])
}
In each case, the increment or decrement runs after every iteration body. The variable changes by exactly one, and the loop condition checks the updated value. Because the statement produces no value, there is no confusion about whether the condition sees the pre‑ or post‑increment value.
You are not limited to using i++ as the post statement. Any simple statement works, including function calls and other assignments. But for the extremely common case of stepping through indices one at a time, i++ and i-- are the most direct and readable choice.
Increment and Decrement with Floating‑Point and Complex Types
Go allows ++ and -- on floating‑point and complex numbers. The operation adds or subtracts the untyped constant 1 of the appropriate type.
var f float64 = 2.5
f++
fmt.Println(f) // 3.5
var c complex128 = 1 + 2i
c--
fmt.Println(c) // (0 + 2i)
Precision and Integer Wrapping:
For floating‑point numbers, incrementing or decrementing by 1 follows normal floating‑point arithmetic. For integers, the value wraps around on overflow and underflow, exactly like += 1 or -= 1. There is no runtime panic.
This behavior is consistent with the rest of Go’s arithmetic. The ++ and -- statements do not introduce any new overflow or rounding rules — they just provide a compact, unambiguous way to say “change by one.”
Why Not Just Use += 1 and -= 1?
The compound assignment operators += and -= can increment or decrement by any amount, including 1. So why does Go keep ++ and --? Two reasons stand out.
First, they communicate intent. When you write i++, you tell the reader “this variable is stepping to the next value.” It signals iteration, traversal, or moving through a sequence. In contrast, x += 1 could mean an arbitrary adjustment that happens to be one — it doesn’t carry the same idiomatic weight. This distinction makes code reviews and maintenance easier because the shape of the operation matches the concept behind it.
Second, they remain the clearest way to express the post‑statement of a for loop. The for i := 0; i < n; i++ pattern is so deeply ingrained in Go that replacing it with i += 1 would feel deliberately unusual. The language retains the forms that developers actually reach for while dropping the dangerous parts (expression evaluation).
Summary
Go’s increment and decrement are statements, not operators. They never return a value, they never appear inside expressions, and they only exist in the postfix form. These restrictions remove a source of undefined behavior and subtle bugs that have existed in C‑family languages for decades.
When you need to step a variable forward or backward by one, write i++ or i-- on its own line. If you need the old value and the increment, write two lines. In a for loop, use i++ as the post statement and trust that it will run after each iteration without side‑effect surprises.
For iteration that requires a step other than 1, reach for += or -=. For any situation where the old value matters, separate the increment from the expression that uses the value. This separation forces you to be explicit, and that explicitness is exactly what makes Go programs predictable and maintainable.