Skip to content
Theory · Operators · lesson 5 of 9

Comparisons and logic

So far Go's calculator has answered with numbers. But a program constantly needs another kind of answer, "yes" or "no": whether a user is an adult, whether a number falls within a range. A comparison gives such an answer, and its result has type bool:

GO
package main

import "fmt"

func main() {
    age := 20
    adult := age >= 18
    teen := age >= 13 && age <= 19
    fmt.Println(adult, teen) // true false
}

Let's walk through the example line by line:

  1. age := 20 declares the age.
  2. adult := age >= 18 holds for 20, so adult is true.
  3. teen := age >= 13 && age <= 19: age >= 13 is true, but 20 <= 19 is not. The && operator requires both sides to be true, so teen is false.
  4. fmt.Println(adult, teen) prints true false.

Six comparison operators

Go has six comparison operators:

  • == is equal;
  • != is not equal;
  • < is less than;
  • <= is less than or equal;
  • > is greater than;
  • >= is greater than or equal.

A double == checks equality, while a single = assigns a value. Only values of the same type can be compared: for an n of type int, the expression n < 2.5 does not compile.

Logical operators

Logical operators work on values of type bool and combine several yes/no answers into one. There are three of them.

&&: AND

The expression a && b gives true only when both operands are true. If at least one of them is false, the result is false.

You use it when all conditions must hold at once. A typical example is a range check: age >= 13 && age <= 19.

||: OR

The expression a || b gives true when at least one operand is true. The result is false only when both operands are false.

You use it when any of the options will do: day == 6 || day == 7 holds for both Saturday and Sunday.

!: NOT

The ! operator goes before a single operand and turns true into false and back: !adult is true when adult is false.

! has a trap: it applies only to the nearest operand. To negate a comparison, wrap it in parentheses: !(age >= 18). Without them, !age >= 18 does not compile.

Logical operators do not accept a number in place of a bool. For an x of type int, the expression !x does not compile.

Order of evaluation

In one expression, operators run in this order:

  1. arithmetic: n%2 == 0 means (n%2) == 0;
  2. comparisons;
  3. &&;
  4. ||.

&& groups its operands before || does, the way multiplication groups before addition. So a || b && c means a || (b && c). Parentheses make that order visible, and they are never wrong.

Short-circuit evaluation

Picture a bouncer at a club door. He lets a guest in if the guest has a ticket and is at least 18. If there is no ticket, the bouncer does not ask about age: the answer is "no" anyway.

&& and || behave the same way. They evaluate the left operand first. If it already settles the answer, the right operand is not evaluated at all:

  • && skips its right operand when the left one is false;
  • || skips its right operand when the left one is true.

This rule is called short-circuit evaluation:

GO
package main

import "fmt"

func isEven(n int) bool {
    fmt.Print("isEven ")
    return n%2 == 0
}

func main() {
    fmt.Println(isEven(3) && isEven(4)) // isEven false
    fmt.Println(isEven(4) || isEven(3)) // isEven true
}

fmt.Print prints without a line break, so the word and the result share a line. Let's go through both lines of main:

  1. isEven(3) && isEven(4) prints isEven false: isEven(3) returned false, and isEven(4) was never called.
  2. isEven(4) || isEven(3) prints isEven true: isEven(4) returned true, and isEven(3) was never called.

That is why the right operand can rely on the left one. The expression d != 0 && n/d > 2 never divides by zero.

A bouncer may start with either question, but Go may not: it always evaluates the left operand first. So the order of operands matters. Short-circuit evaluation is a common interview question: you are shown an expression with a function call to the right of && and asked what the program prints.

Common mistake

A range check is written the way it is in math:

GO
x := 15
fmt.Println(0 < x < 10) // ✗
TEXT
invalid operation: 0 < x < 10 (mismatched types untyped bool and untyped int)

The program does not compile. The expression reads as (0 < x) < 10: the left side becomes a bool, and a bool cannot be compared with a number. A range is checked with two comparisons: 0 < x && x < 10.

Key points

  • A comparison gives a bool; == checks equality, and = assigns.
  • && is true when both operands are, || when at least one is; && groups before ||.
  • The right operand of && is skipped when the left is false, and that of || when the left is true.
  • A range is checked with two comparisons: 0 < x && x < 10.

Subscribe to take the course

The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.

Sign in another way