What the not operator does
The ! operator turns true into false and false into true. It goes in front of a single boolean value and takes no value on its left, which is why it is called a unary operator.
isSunny := true
fmt.Println(!isSunny) // false
fmt.Println(!!isSunny) // true
It is useful when the condition you care about is the opposite of a value you already have. Instead of adding a second variable such as isRainy, you flip the one you have.
The lesson's exercise
The code declares a boolean variable:
var isSunny bool = true
Here the type is written out: var isSunny bool = true means the same as isSunny := true.
Step 1: the if statement
Write an if whose condition is !isSunny. It is true only when isSunny is false, so the body, which prints "Learning to code", runs on days that are not sunny. Braces around the body are required in Go, and the condition needs no parentheses.
Step 2: the else branch
Add } else { and print "Going to the beach". The else runs whenever the if condition is false. Because the condition is !isSunny, that means isSunny is true, so it is sunny and the beach wins.
The solution in Go
var isSunny bool = true
if !isSunny {
fmt.Println("Learning to code")
} else {
fmt.Println("Going to the beach")
}
Since isSunny is true, !isSunny is false, the if body is skipped, and the program prints Going to the beach. Set isSunny to false and it prints Learning to code.
Using ! with comparisons
You can negate a whole comparison by wrapping it in parentheses:
n := 20
fmt.Println(!(n > 18)) // false
fmt.Println(n <= 18) // false
Both lines print false: "not greater than 18" is the same as "at most 18". The parentheses matter, because ! applies to whatever directly follows it. Without them, !n > 18 would try to negate the number n first.
For a plain comparison, the opposite operator is usually easier to read: write n <= 18 rather than !(n > 18). Keep ! for boolean variables and for bigger expressions, where negating one group reads well, like !(a && b).
Negating a function result
The operand can be anything that produces a bool, including a function call:
func isWeekend(day string) bool {
return day == "Sat" || day == "Sun"
}
func main() {
for _, day := range []string{"Mon", "Sat"} {
if !isWeekend(day) {
fmt.Println(day, "workday")
} else {
fmt.Println(day, "weekend")
}
}
}
This prints Mon workday and then Sat weekend. Reading !isWeekend(day) aloud as "not weekend" is a good habit, since a condition that reads naturally is easier to get right.
Negating a group
Negating && or || follows a pattern known as De Morgan's laws: !(a && b) equals !a || !b, and !(a || b) equals !a && !b. Each ! flips the operator between "and" and "or" as it moves inside the parentheses. With a true and b false, both !(a && b) and !a || !b print true.
Go details worth knowing
!only works on booleans. Go has no "truthy" or "falsy" values. Withx := 1, the expression!xdoes not compile:operator ! not defined on x (variable of type int). Writex == 0to ask whether a number is zero.- It is not
!=.!=is the "not equal" comparison between two values, while!flips one boolean.a != band!(a == b)give the same result. - Precedence.
!binds tighter than&&and||, so!a && bmeans(!a) && b. Add parentheses when you want to negate a whole group. - Prefer positive names. A variable called
isSunnyis easier to combine with!than one calledisNotSunny, because!isNotSunnyis a double negative that the reader has to untangle. Name booleans after what is true, and flip them at the point of use. - The else layout.
elsemust start on the same line as the closing brace of theifbody.
Common mistakes
- Forgetting the
!. Withif isSunny, the messages swap: sunny days printLearning to code. - Double negatives.
!!isSunnyis the same asisSunny. If a condition has two!in a row, simplify it. - Using
!on a number or string. It is a compile error, not a runtime check. - Negating one part of a comparison.
!n > 18is invalid; negate the whole comparison with!(n > 18).
Key takeaways
!bflips a boolean: true becomes false and false becomes true.- Only booleans can be negated; compare numbers explicitly.
- Wrap a comparison or group in parentheses to negate all of it.
- An
elsebranch covers every case where theifcondition is false.