Why combine operators
Real rules are rarely a single comparison. "Special students may enter, and so may anyone aged 18 to 30" has an or in the middle and an and inside one side. Go lets you build such rules from && (and), || (or) and ! (not), as long as each piece is a boolean expression.
A short refresher: a && b is true only when both sides are true, and a || b is true when at least one side is.
Precedence: who goes first
When one condition mixes && and ||, Go groups the && parts first, in the same way that multiplication happens before addition. Both of the following lines are evaluated like this:
t, f := true, false
fmt.Println(t || f && f) // true: same as t || (f && f)
fmt.Println((t || f) && f) // false: the parentheses change the grouping
The first line prints true and the second prints false, with identical operands. Parentheses are free, so use them whenever a reader would have to stop and think about the order, even where the order is already right.
The lesson's exercise
The code declares two variables:
var specialStudent bool = false
var age int = 23
The entry rule is: let the student in if specialStudent is true, or if age is between 18 and 30, both ends included.
Step 1: the if statement
"Between 18 and 30" is two comparisons that must both hold: age >= 18 && age <= 30. Go has no chained comparison like 18 <= age <= 30, so the age appears twice. Because both ends are included, the operators are >= and <=. Wrap that pair in parentheses, then join it to specialStudent with ||.
Step 2: the else branch
Add } else { and print "Not allowed". It runs for anyone who fails both checks: not special, and younger than 18 or older than 30.
The solution in Go
var specialStudent bool = false
var age int = 23
if (specialStudent || (age >= 18 && age <= 30)) {
fmt.Println("Let him in!")
} else {
fmt.Println("Not allowed")
}
Reading it from the inside out: age >= 18 && age <= 30 is true for 23, so the || is true even though specialStudent is false, and the program prints Let him in!.
The outermost parentheses are allowed but not needed, because Go does not require parentheses around an if condition. Most Go code, and the gofmt tool, leaves them out; the inner parentheses are the useful ones.
Trying different ages
With specialStudent set to false, the rule behaves like this:
| age | result |
|---|---|
| 17 | Not allowed |
| 18 | Let him in! |
| 30 | Let him in! |
| 31 | Not allowed |
With specialStudent set to true, every age is let in, since the left side of || is already true and Go does not even evaluate the age comparisons.
Breaking a rule into pieces
When a rule gets long, name its parts. Boolean variables cost nothing and make the final condition read like the rule itself:
inRange := age >= 18 && age <= 30
if specialStudent || inRange {
fmt.Println("Let him in!")
}
This behaves exactly like the version with the age check written inline. Use whichever form reads better; for a rule with two or three parts, the inline form is fine.
Go details worth knowing
- Short-circuiting.
&&stops at the first false operand and||stops at the first true one. Later operands are not evaluated, which matters for operands with side effects or ones that would fail, such as an index that might be out of range. - Booleans only. Every operand must be a
bool. Comparing with== trueis legal but redundant; writespecialStudentalone. - The else layout. Go requires
elseon the same line as the closing brace. On its own line, the program does not compile. - Declared variables must be used. If you remove the use of
age, the compiler reportsdeclared and not used.
Common mistakes
- Using
||inside the age range.age >= 18 || age <= 30is true for every integer. A range needs both bounds to hold, which is&&. - Exclusive bounds. Writing
age > 18 && age < 30rejects 18 and 30, which the rule allows. - Dropping the inner parentheses.
specialStudent || age >= 18 && age <= 30happens to mean the same thing, but(specialStudent || age >= 18) && age <= 30does not: it would reject a special student older than 30. - Chained comparisons.
18 <= age <= 30is a compile error in Go.
Key takeaways
&&binds tighter than||; parentheses override the order and make it visible.- A range check is two comparisons joined with
&&. - Evaluation stops early once the result is known.
- The
elsebranch handles everyone who fails every check above it.