Beginner

Operators in Go

Explore arithmetic, comparison, logical, bitwise, and assignment operators in Go with practical Docker-ready examples

Operators are the verbs of a programming language — the symbols that combine values and variables into expressions. Go’s operator set is deliberately small and conventional, inheriting most of its notation from C while trimming the more error-prone corners.

As a statically typed language with strong typing, Go enforces operand types strictly. You cannot add an int to a float64 without explicit conversion, and there is no implicit truthiness — only the bool type is valid in conditions. This tutorial walks through every operator category Go supports, including a few that surprise newcomers (such as &^ and the statement-form ++).

By the end you will be able to read and write Go expressions confidently, know which operators are statements (not expressions), and understand how Go’s type rules shape arithmetic.

Arithmetic Operators

Go provides the standard set: +, -, *, /, and %. Integer division truncates toward zero, while floating-point division behaves as expected. There is no exponent operator — use math.Pow for that.

Comparison Operators

The six comparison operators (==, !=, <, >, <=, >=) all yield a bool. Two values must be of comparable types; mixing an int and an int64 is a compile-time error without conversion.

Logical Operators

&&, ||, and ! are short-circuit logical operators that only operate on bool values. Unlike Python or JavaScript, Go will not let you write if x where x is an integer.

Bitwise Operators

Go offers the usual &, |, ^, <<, >>, plus a rare one: &^ (AND NOT, also called bit clear). a &^ b zeroes every bit in a that is set in b.

Assignment and Increment

Each binary arithmetic and bitwise operator has a compound assignment form (+=, *=, &^=, etc.). Go also has ++ and -- — but unlike C, they are statements, not expressions. You cannot write b := a++.

Comprehensive Example

Create a file named operators.go:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package main

import "fmt"

func main() {
    // Arithmetic
    a, b := 17, 5
    fmt.Println("Arithmetic:")
    fmt.Println("a + b =", a+b)
    fmt.Println("a - b =", a-b)
    fmt.Println("a * b =", a*b)
    fmt.Println("a / b =", a/b) // integer division: truncates
    fmt.Println("a % b =", a%b)

    // Floating-point division requires float operands
    x, y := 17.0, 5.0
    fmt.Println("x / y =", x/y)

    // Comparison — always yields bool
    fmt.Println("\nComparison:")
    fmt.Println("a == b:", a == b)
    fmt.Println("a != b:", a != b)
    fmt.Println("a > b:", a > b)
    fmt.Println("a <= b:", a <= b)

    // Logical — short-circuit, bool only
    t, f := true, false
    fmt.Println("\nLogical:")
    fmt.Println("t && f:", t && f)
    fmt.Println("t || f:", t || f)
    fmt.Println("!t:", !t)

    // Bitwise: p = 1100, q = 1010
    p, q := 12, 10
    fmt.Println("\nBitwise:")
    fmt.Println("p & q  =", p&q)   // AND  -> 8
    fmt.Println("p | q  =", p|q)   // OR   -> 14
    fmt.Println("p ^ q  =", p^q)   // XOR  -> 6
    fmt.Println("p &^ q =", p&^q)  // AND NOT -> 4
    fmt.Println("p << 2 =", p<<2)  // left shift
    fmt.Println("p >> 1 =", p>>1)  // right shift

    // Compound assignment
    n := 10
    n += 5
    fmt.Println("\nAssignment:")
    fmt.Println("n += 5 ->", n)
    n *= 2
    fmt.Println("n *= 2 ->", n)
    n %= 7
    fmt.Println("n %= 7 ->", n)

    // Increment is a statement, not an expression
    c := 0
    c++
    c++
    fmt.Println("c after c++ twice:", c)

    // String concatenation uses +
    greet := "Hello, " + "Go!"
    fmt.Println("\nString:")
    fmt.Println(greet)
}

Operator Precedence

Go has only five precedence levels for binary operators — far fewer than C. From highest to lowest:

  1. * / % << >> & &^
  2. + - | ^
  3. == != < <= > >=
  4. &&
  5. ||

Unary operators (!, -, ^, *, &) bind tightest. When in doubt, parenthesize.

Create a file named precedence.go:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
package main

import "fmt"

func main() {
    // Multiplication binds tighter than addition
    fmt.Println(2 + 3*4)   // 14, not 20

    // && binds tighter than ||
    fmt.Println(true || false && false) // true (false && false evaluated first)

    // Bitwise & shares level 1 with * — surprising!
    // 1 + 2 & 3  parses as  1 + (2 & 3)  ->  1 + 2  ->  3
    fmt.Println(1 + 2&3)

    // Comparison yields bool, so chaining like a < b < c is a type error.
    // Use && instead:
    a, b, c := 1, 2, 3
    fmt.Println(a < b && b < c)
}

Running with Docker

1
2
3
4
5
6
7
8
# Pull the official Go image
docker pull golang:1.23

# Run the comprehensive operators example
docker run --rm -v $(pwd):/app -w /app golang:1.23 go run operators.go

# Run the precedence example
docker run --rm -v $(pwd):/app -w /app golang:1.23 go run precedence.go

Expected Output

Output of operators.go:

Arithmetic:
a + b = 22
a - b = 12
a * b = 85
a / b = 3
a % b = 2
x / y = 3.4

Comparison:
a == b: false
a != b: true
a > b: true
a <= b: false

Logical:
t && f: false
t || f: true
!t: false

Bitwise:
p & q  = 8
p | q  = 14
p ^ q  = 6
p &^ q = 4
p << 2 = 48
p >> 1 = 6

Assignment:
n += 5 -> 15
n *= 2 -> 30
n %= 7 -> 2
c after c++ twice: 2

String:
Hello, Go!

Output of precedence.go:

14
true
3
true

Key Concepts

  • No implicit conversionsint + float64 is a compile error. Convert explicitly with float64(x) or int(y).
  • Integer division truncates17 / 5 is 3, not 3.4. Use floating-point operands to get a fractional result.
  • bool is its own type — conditions must evaluate to bool. There is no truthiness for ints, strings, or pointers.
  • &^ is unique — the bit-clear operator zeroes bits in the left operand wherever the right operand has bits set; useful for clearing flags.
  • ++ and -- are statements — they cannot appear inside expressions or assignments. b := a++ does not compile.
  • + doubles as string concatenation — but only between two strings; mixing a string and an integer is a compile error.
  • Precedence is flatter than C — only five binary levels. Notably, & shares precedence with *, so 1 + 2 & 3 may not parse the way you expect.
  • No ternary operator — Go intentionally omits ?:; use a regular if statement instead.

Running Today

All examples can be run using Docker:

docker pull golang:1.23
Last updated:

Comments

Loading comments...

Leave a Comment

2000 characters remaining