Arithmetic and Assignment Operators
Learn about arithmetic operators (+, -, *, /, %) for calculations, assignment operators (=, +=, -=, etc.) for storing values, and the increment and decrement operators (++, --) in Go.
Go provides a small but powerful set of operators for performing calculations, storing results, and adjusting numeric values. This document covers the three operator families that form the backbone of almost every computation in a Go program: arithmetic operators, assignment operators, and the increment/decrement operators.
Arithmetic operators let you do the math—addition, subtraction, multiplication, division, and remainder. Assignment operators let you store those results into variables, with convenient shorthand forms for updating a value without repeating the variable name. Increment and decrement give you a concise way to add or subtract 1, but with important rules that are unique to Go.
All three work together in the expressions you will write inside functions, loops, and conditional blocks. Understanding them thoroughly early on removes one of the biggest sources of silent bugs for new Go developers.
Arithmetic Operators
Arithmetic operators perform mathematical calculations on numeric values. They work on integers, floating-point numbers, and in some cases (like the + operator) even on strings for concatenation—but that string behavior is outside the scope of this document.
The six arithmetic operators in Go are:
| Operator | Name | Example (a = 10, b = 3) | Result |
|---|---|---|---|
+ | Addition | a + b | 13 |
- | Subtraction | a - b | 7 |
* | Multiplication | a * b | 30 |
/ | Division | a / b | 3 |
% | Remainder | a % b | 1 |
- (unary) | Negation | -a | -10 |
+ (unary) | Positive sign | +a | 10 |
The addition, subtraction, multiplication, and division operators work exactly as you would expect from basic arithmetic. The remainder operator (%) returns the leftover after integer division—for example, 10 divided by 3 is 3 with a remainder of 1, so 10 % 3 is 1.
The unary - operator negates a numeric value: if x is 5, then -x is -5. The unary + operator technically exists but is rarely used; it simply returns the value unchanged. Both unary operators have higher precedence than the binary ones, meaning -a * b is equivalent to (-a) * b, not -(a * b).
Integer Division and the Remainder Operator
The most common beginner mistake with Go’s arithmetic operators involves division with integers.
Integer Division Truncates:
When both operands of the / operator are integers, Go performs integer division and discards any fractional part. The expression 5 / 2 evaluates to 2, not 2.5. If you need a decimal result, convert at least one operand to a floating-point type first.
package main
import "fmt"
func main() {
a := 5
b := 2
// Integer division: fractional part discarded
fmt.Println(a / b) // prints 2
// Floating-point division: one operand is float64
fmt.Println(float64(a) / float64(b)) // prints 2.5
// Remainder: what is left after integer division
fmt.Println(a % b) // prints 1
}
The integer division behavior catches developers who move from languages where / always produces a decimal. In Go, the types of the operands determine the result type. The remainder operator % only works on integers—you cannot use it with float64 values. If you need the remainder of a floating-point division, use math.Mod from the standard library.
The expression float64(a) / float64(b) is a type conversion, not a cast. It creates a new float64 value from the integer, leaving the original variable unchanged. This explicit conversion requirement is one way Go makes programmers think about numeric types rather than silently converting them.
Arithmetic Operators in Everyday Go
Arithmetic operators appear in almost every program that manipulates numbers—calculating totals, adjusting coordinates, computing indices. In loops, they form the heart of counter updates. In business logic, they compute discounts, taxes, or array sizes. They are as fundamental as the variables they operate on.
A mental model that helps: think of each arithmetic operator as a tiny function that takes two numbers and returns one number. You can chain them, but operator precedence matters. Multiplication and division happen before addition and subtraction unless you use parentheses to group operations explicitly.
Precedence and Clarity:
Go follows standard mathematical precedence: *, /, % are evaluated before +, -. When in doubt, add parentheses to make your intent obvious. There is no performance penalty for extra parentheses, and they prevent logic errors.
Assignment Operators
Assignment operators store a value into a variable. The simplest one, =, takes the value on the right-hand side and copies it into the variable on the left-hand side. The left-hand side must always be something that can hold a value—a variable, a struct field, an array or slice element, or a pointer dereference. In compiler terminology, it must be an addressable lvalue.
package main
import "fmt"
func main() {
var x int
x = 42 // assigns 42 to x
fmt.Println(x) // prints 42
}
The assignment = is fundamentally different from the equality operator ==—a distinction that causes confusion for beginners coming from mathematics or from languages that use = for comparison. In Go, a single equals sign always means "store this value," never "are these equal?"
Compound Assignment Operators
When you want to update a variable using its current value—add 5 to it, divide it by 2—you could write the operation in full: x = x + 5. Go provides shorthand compound assignment operators that combine an arithmetic operation with assignment in one step.
| Operator | Equivalent Expression |
|---|---|
+= | x = x + value |
-= | x = x - value |
*= | x = x * value |
/= | x = x / value |
%= | x = x % value |
package main
import "fmt"
func main() {
total := 10
total += 5 // total becomes 15
fmt.Println(total)
total *= 2 // total becomes 30
fmt.Println(total)
total %= 7 // 30 % 7 = 2
fmt.Println(total)
}
The compound assignment operators are not merely cosmetic. They reduce repetition and make the programmer's intent explicit: "update this variable by this amount." In large codebases, a long expression on the right side of a regular assignment can obscure the fact that the variable is being modified in place. A += at the beginning of the line signals the update immediately.
Each compound assignment works exactly like the expanded form, so integer division truncation still applies with /=. The same type rules apply: total /= 3 on an integer variable performs integer division.
Clear and Idiomatic:
Using compound assignment operators like += and *= is idiomatic in Go. They make the code more concise without sacrificing readability and are commonly found in loops, accumulators, and state updates throughout the standard library and production codebases.
Assignment vs. Short Variable Declaration
You will often see the := operator in Go. It is not an assignment operator—it is a short variable declaration. It declares a new variable and assigns an initial value in one step.
x := 10 // declares x and assigns 10
x = 20 // assigns a new value to the already-declared x
Once a variable exists, use = to change its value. Attempting to use := on a variable that is already declared in the same scope will cause a compile error, unless at least one new variable is being declared on the left side.
Increment and Decrement
The ++ and -- operators add 1 or subtract 1 from a numeric variable. They are common in loops, counters, and anywhere a value needs to move by exactly one unit.
Go handles these operators differently from most C-family languages, and this is one of the first surprises developers encounter when learning Go.
++ and -- Are Statements, Not Expressions:
In Go, x++ and x-- are statements, not expressions. They stand alone on a line and do not produce a value that you can use in another expression. Writing y := x++ or if x++ > 10 {} will not compile. This is a deliberate language design choice that prevents ambiguity and side-effect bugs.
package main
import "fmt"
func main() {
counter := 0
counter++ // counter becomes 1
counter++ // counter becomes 2
fmt.Println(counter) // prints 2
counter-- // counter becomes 1
fmt.Println(counter) // prints 1
}
You cannot chain or nest increment and decrement. You cannot write x = y++, and you cannot use prefix forms like ++x—Go only supports postfix x++ and x--. This restriction simplifies code and eliminates entire categories of off-by-one and evaluation-order bugs that plague other languages.
In practice, this means that when you need to use an incremented value inside a larger expression, you must increment on one line and use the variable on the next. This extra line may feel verbose, but it makes the order of operations completely unambiguous.
A common use case is the post-statement of a for loop. The for loop's third clause is a statement, so i++ works naturally there:
for i := 0; i < 10; i++ {
fmt.Println(i)
}
Even though i++ appears inside a loop construct, it is still a standalone statement—the loop simply executes it after each iteration.
Beginners often try to use ++ as a shortcut for += 1 inside expressions, especially when porting code from JavaScript, C, or Java. The compiler will reject this, and the error message will point directly to the misuse. Accepting the statement-only rule early on avoids frustration and leads to cleaner Go code.
Summary
Arithmetic, assignment, and increment/decrement operators form the computational core of every Go program. Arithmetic operators perform the math, assignment operators store the results, and increment/decrement adjust values by one in a way that is intentionally limited to prevent subtle bugs.
The biggest takeaways from this document are the Go-specific rules that differ from other languages: integer division truncates unless you convert to a floating-point type, compound assignment operators provide clean shorthands for updating variables, and ++/-- are statements—never expressions—and only work in postfix form. Internalizing these three points will save you hours of debugging.