Go Operators
Operators are symbols that perform an operation on one or more values — arithmetic, comparison, logical evaluation, assignment, and bit manipulation. They are the building blocks of every expression in a Go program.
Categories of Operators in Go
Go groups operators into five main categories, each covered in its own section below:
- Arithmetic operators
- Assignment operators
- Comparison operators
- Logical operators
- Bitwise operators
1. Arithmetic Operators
Arithmetic operators perform basic mathematical calculations.
| Operator | Name | Description | Example |
|---|---|---|---|
+ | Addition | Adds two values | x + y |
- | Subtraction | Subtracts one value from another | x - y |
* | Multiplication | Multiplies two values | x * y |
/ | Division | Divides one value by another | x / y |
% | Modulus | Returns the remainder of division | x % y |
++ | Increment | Increases a variable's value by 1 | x++ |
-- | Decrement | Decreases a variable's value by 1 | x-- |
package main
import "fmt"
func main() {
a := 18
b := 4
fmt.Println("Addition:", a+b)
fmt.Println("Subtraction:", a-b)
fmt.Println("Multiplication:", a*b)
fmt.Println("Division:", a/b)
fmt.Println("Modulus:", a%b)
counter := 5
counter++ // increment
fmt.Println("After Increment:", counter)
counter-- // decrement
fmt.Println("After Decrement:", counter)
}
Expected output:
Addition: 22
Subtraction: 14
Multiplication: 72
Division: 4
Modulus: 2
After Increment: 6
After Decrement: 5
Important Notes
Integer division truncates. When both operands are integers, / discards the remainder rather than rounding:
result := 7 / 2 // result = 3, not 3.5
To get a fractional result, convert to a floating-point type first:
result := float64(7) / float64(2) // result = 3.5
++ and -- are statements, not expressions. Unlike C, Java, or JavaScript, Go does not allow ++/-- to be used inside a larger expression. You cannot write y = x++ or pass x++ as a function argument — x++ must stand alone on its own line.
2. Assignment Operators
Assignment operators assign a value to a variable, optionally combining that assignment with an arithmetic or bitwise operation.
| Operator | Example | Equivalent To |
|---|---|---|
= | x = 5 | Assign value directly |
+= | x += 3 | x = x + 3 |
-= | x -= 3 | x = x - 3 |
*= | x *= 3 | x = x * 3 |
/= | x /= 3 | x = x / 3 |
%= | x %= 3 | x = x % 3 |
&= | x &= 3 | x = x & 3 |
|= | x |= 3 | x = x | 3 |
^= | x ^= 3 | x = x ^ 3 |
<<= | x <<= 2 | x = x << 2 |
>>= | x >>= 2 | x = x >> 2 |
package main
import "fmt"
func main() {
points := 20
points += 10 // add and assign
points *= 2 // multiply and assign
fmt.Println("Final Points:", points)
}
Expected output:
Final Points: 60
package main
import "fmt"
func main() {
value := 12
value -= 2 // 10
value *= 3 // 30
value /= 5 // 6
value %= 4 // 2
fmt.Println("Final Value:", value)
}
Compound assignment operators exist for the same reason as in most languages: they reduce repetition and make code easier to scan, and they're especially common in loop counters and running totals.
3. Comparison Operators
Comparison operators compare two values and always produce a bool result — Go has no implicit 1/0 fallback the way C does.
| Operator | Name | Example |
|---|---|---|
== | Equal to | x == y |
!= | Not equal to | x != y |
> | Greater than | x > y |
< | Less than | x < y |
>= | Greater than or equal to | x >= y |
<= | Less than or equal to | x <= y |
package main
import "fmt"
func main() {
x := 15
y := 10
fmt.Println("x > y:", x > y)
fmt.Println("x == y:", x == y)
fmt.Println("x != y:", x != y)
}
package main
import "fmt"
func main() {
age := 18
if age >= 18 {
fmt.Println("Eligible to vote")
} else {
fmt.Println("Not eligible to vote")
}
}
4. Logical Operators
Logical operators combine or invert boolean conditions.
| Operator | Name | Description |
|---|---|---|
&& | Logical AND | true only if both operands are true |
|| | Logical OR | true if at least one operand is true |
! | Logical NOT | Inverts a boolean value |
Logical AND (&&)
package main
import "fmt"
func main() {
age := 20
hasID := true
if age >= 18 && hasID {
fmt.Println("Entry allowed.")
} else {
fmt.Println("Entry denied.")
}
}
Both conditions must be true for the if branch to run.
Logical OR (||)
package main
import "fmt"
func main() {
isMember := false
hasCoupon := true
if isMember || hasCoupon {
fmt.Println("Discount applied.")
} else {
fmt.Println("No discount available.")
}
}
Only one of the two conditions needs to be true.
Logical NOT (!)
package main
import "fmt"
func main() {
isRaining := false
if !isRaining {
fmt.Println("You can go outside.")
} else {
fmt.Println("Stay indoors.")
}
}
!isRaining reads as "it is NOT raining" — the boolean is inverted.
Combining Logical Operators
package main
import "fmt"
func main() {
marks := 85
attendance := 75
if (marks > 80 && attendance > 70) || marks > 90 {
fmt.Println("Eligible for reward.")
} else {
fmt.Println("Not eligible.")
}
}
A student qualifies if they have good marks and good attendance, or exceptionally high marks on their own. Parentheses make the intended grouping explicit and are good practice whenever && and || are combined in one expression.
Short-circuit evaluation: Go evaluates && and || left to right and stops as soon as the result is determined — in a() && b(), if a() returns false, b() is never called at all. This is more than a performance detail: it's a common pattern for avoiding errors, such as writing slice != nil && slice[0] == target, where checking slice != nil first prevents a panic from indexing a nil slice.
5. Bitwise Operators
Bitwise operators manipulate the individual bits (0s and 1s) that make up an integer's binary representation. They're used in low-level programming, performance-critical code, and anywhere you need to pack multiple flags into a single number.
| Operator | Name | Description |
|---|---|---|
& | Bitwise AND | Sets a bit to 1 only if both corresponding bits are 1 |
| | Bitwise OR | Sets a bit to 1 if at least one corresponding bit is 1 |
^ | Bitwise XOR | Sets a bit to 1 if the corresponding bits differ |
<< | Left shift | Shifts bits left, filling with 0s on the right |
>> | Right shift | Shifts bits right |
package main
import "fmt"
func main() {
a := 5 // binary: 0101
b := 3 // binary: 0011
fmt.Println("AND:", a&b)
fmt.Println("OR:", a|b)
fmt.Println("XOR:", a^b)
fmt.Println("Left Shift:", a<<1)
fmt.Println("Right Shift:", a>>1)
}
Expected output:
AND: 1
OR: 7
XOR: 6
Left Shift: 10
Right Shift: 2
Bitwise AND (&)
package main
import "fmt"
func main() {
a := 6 // binary: 110
b := 3 // binary: 011
result := a & b // 010 (2)
fmt.Println("Bitwise AND result:", result)
}
110 (6)
& 011 (3)
------
010 (2)
Bitwise OR (|)
package main
import "fmt"
func main() {
a := 5 // binary: 101
b := 2 // binary: 010
result := a | b // 111 (7)
fmt.Println("Bitwise OR result:", result)
}
101 (5)
| 010 (2)
------
111 (7)
Bitwise XOR (^)
package main
import "fmt"
func main() {
a := 7 // binary: 111
b := 4 // binary: 100
result := a ^ b // 011 (3)
fmt.Println("Bitwise XOR result:", result)
}
111 (7)
^ 100 (4)
------
011 (3)
Left Shift (<<)
Shifting left by n positions is equivalent to multiplying by 2ⁿ:
package main
import "fmt"
func main() {
value := 4 // binary: 100
result := value << 2 // 10000 (16)
fmt.Println("Left shift result:", result)
}
Right Shift (>>)
Shifting right by n positions is equivalent to integer division by 2ⁿ. For signed integer types, Go performs an arithmetic shift, which preserves the sign bit:
package main
import "fmt"
func main() {
value := 16 // binary: 10000
result := value >> 2 // 00100 (4)
fmt.Println("Right shift result:", result)
}
Practical Use Case: Bit Flags
Bitwise operators are commonly used to set, check, and clear individual flag bits packed into one integer — a technique used in areas like permission systems and low-level protocol headers:
package main
import "fmt"
func main() {
var flags int
// Set bit 1 (turn ON)
flags = flags | (1 << 1)
// Check whether bit 1 is set
if flags&(1<<1) != 0 {
fmt.Println("Bit 1 is ON")
}
// Clear bit 1 (turn OFF)
flags = flags &^ (1 << 1)
fmt.Println("Final flags value:", flags)
}
Note: Go provides a dedicated "AND NOT" operator, &^, specifically for clearing bits — flags &^ mask clears every bit in flags that is set in mask. This is more idiomatic Go than writing flags & ^mask (bitwise NOT combined with AND), though both produce the same result.