A program that only stores values isn’t very useful. The whole point is to do something with them — add them, compare them, decide what to do based on their state. This lesson covers the tools Go gives you for that: operators and conditional statements.
Arithmetic operators
The basic math operators work the way you’d expect:
package main
import "fmt"
func main() {
a := 10
b := 3
fmt.Println("Sum: ", a+b)
fmt.Println("Difference:", a-b)
fmt.Println("Product: ", a*b)
fmt.Println("Quotient: ", a/b)
fmt.Println("Remainder: ", a%b)
}
Sum: 13
Difference: 7
Product: 30
Quotient: 3
Remainder: 1
A few things to notice:
- Integer division drops the decimal part.
10 / 3is3, not3.33. If you need a decimal result, usefloat64:float64(a) / float64(b). %is the modulo (remainder) operator.10 % 3 = 1because 10 divided by 3 leaves a remainder of 1. It’s enormously useful — for instance,n % 2 == 0checks ifnis even.
Assignment shortcuts
Adding to a variable is so common Go gives you a shortcut:
// inside main()
score := 0
score += 10 // same as: score = score + 10
score -= 3 // same as: score = score - 3
score *= 2 // same as: score = score * 2
score /= 7 // same as: score = score / 7
fmt.Println(score)
There’s also ++ and -- for the very common case of adding/subtracting 1:
// inside main()
count := 0
count++ // count is now 1
count++ // count is now 2
count-- // count is now 1
fmt.Println(count)
Unlike C or JavaScript,
count++is a statement, not an expression. You can’t writex := count++. Keep it on its own line.
Comparison operators
Comparison operators compare two values and return a bool:
package main
import "fmt"
func main() {
a := 10
b := 20
fmt.Println("a == b:", a == b)
fmt.Println("a != b:", a != b)
fmt.Println("a < b:", a < b)
fmt.Println("a > b:", a > b)
fmt.Println("a <= b:", a <= b)
fmt.Println("a >= b:", a >= b)
}
a == b: false
a != b: true
a < b: true
a > b: false
a <= b: true
a >= b: false
| Operator | Meaning |
|---|---|
== | equal to |
!= | not equal to |
< | less than |
> | greater than |
<= | less than or equal |
>= | greater than or equal |
Comparison works on numbers, strings, and booleans. For strings, it compares lexically — "apple" < "banana" is true.
Logical operators
Combine boolean expressions with these:
// inside main()
isLoggedIn := true
isAdmin := false
fmt.Println(isLoggedIn && isAdmin) // AND: true only if both are true
fmt.Println(isLoggedIn || isAdmin) // OR: true if either is true
fmt.Println(!isLoggedIn) // NOT: flips the value
false
true
false
Go uses short-circuit evaluation: in a && b, if a is already false, Go never even looks at b. Same for ||: if a is true, b is skipped. This matters when b is an expensive function call or could crash if a was false.
The if statement
if is how you make decisions:
package main
import "fmt"
func main() {
age := 18
if age >= 18 {
fmt.Println("You can vote.")
}
}
You can vote.
Notice there are no parentheses around the condition — that’s the Go style. The braces { }, however, are required, even for a single-line block. (This is one of Go’s safety rules — it eliminates a whole category of “I forgot the braces” bugs.)
else
An if on its own only handles one branch — what happens when the condition is true. Pair it with else to also handle the case when it’s false:
package main
import "fmt"
func main() {
var num int
fmt.Println("Enter a number: ")
fmt.Scanf("%d", &num)
if num%2 == 0 {
fmt.Printf("%d is an even number\n", num)
} else {
fmt.Printf("%d is an odd number\n", num)
}
}
Enter a number:
7
7 is an odd number
When num % 2 == 0 is true, the first block runs; otherwise the else block runs. Exactly one of the two will execute.
This example also sneaks in two things you’ll see often: fmt.Scanf reads input from the terminal using the same verbs as Printf (%d for an integer), and the & in front of num passes its memory address so Scanf can write into it. Pointers get a proper treatment in the next section — for now, just remember that Scanf always wants & in front of each variable.
else if
// inside main()
score := 75
if score >= 90 {
fmt.Println("Grade: A")
} else if score >= 80 {
fmt.Println("Grade: B")
} else if score >= 70 {
fmt.Println("Grade: C")
} else {
fmt.Println("Grade: F")
}
Grade: C
Conditions are checked top to bottom; the first one that matches runs and the rest are skipped.
if with a short statement
Go has a powerful shortcut: you can declare a variable inside an if, and that variable is only visible inside the if/else blocks:
package main
import "fmt"
func main() {
var num int
fmt.Println("Enter a number: ")
fmt.Scanf("%d", &num)
if n := num / 2; num%2 == 0 {
fmt.Printf("%d is an even number; half of it is %d\n", num, n)
} else {
fmt.Printf("%d is an odd number; half of it (rounded down) is %d\n", num, n)
}
// n is no longer accessible here
}
Enter a number:
7
7 is an odd number; half of it (rounded down) is 3
n := num / 2 runs first, then the condition num%2 == 0 is checked. Both branches can use n, but it’s gone the moment the if/else ends — keeping it scoped tight prevents accidental reuse later.
This pattern is everywhere in Go — especially when checking errors, which we’ll cover later.
The switch statement
When you’d write a chain of if/else if with the same variable, switch is cleaner:
package main
import "fmt"
func main() {
day := "Tuesday"
switch day {
case "Monday":
fmt.Println("Start of the week")
case "Tuesday", "Wednesday", "Thursday":
fmt.Println("Mid-week")
case "Friday":
fmt.Println("Almost weekend")
case "Saturday", "Sunday":
fmt.Println("Weekend!")
default:
fmt.Println("Unknown day")
}
}
Mid-week
A few things to notice:
- Each
casecan match multiple values separated by commas - Once a case matches, only its block runs — Go doesn’t “fall through” into the next case automatically (a common gotcha in C and Java). No need for
break. defaultruns if no case matches; it’s optional
Matching characters
A switch shines when you want to accept a few “equivalent” inputs — for example, treating y and Y as the same answer to a yes/no prompt:
package main
import "fmt"
func main() {
fmt.Printf("Do you want to subscribe? y/n : ")
var c byte
fmt.Scanf("%c", &c)
switch c {
case 'y', 'Y':
fmt.Println("Thank you!")
case 'n', 'N':
fmt.Println("No Problem!")
default:
fmt.Println("Invalid input")
}
}
Do you want to subscribe? y/n : Y
Thank you!
Two small details worth pointing out:
'y'and'Y'are character literals — single-quoted characters that compare cleanly against abyte. (Use double quotes only for strings.)fmt.Printf("...y/n : ")has no\n, so the cursor stays on the same line and the user’s keystroke appears right after the prompt. That’s a small but useful trick whenever you’re asking for input.
switch without an expression
You can also use switch as a cleaner alternative to long if/else if chains:
// inside main()
score := 75
switch {
case score >= 90:
fmt.Println("A")
case score >= 80:
fmt.Println("B")
case score >= 70:
fmt.Println("C")
default:
fmt.Println("F")
}
This pattern is very Go-flavored — many developers prefer it over if/else if chains because it’s easier to scan visually.
What’s next
You can now make decisions in your programs. The remaining piece of basic control flow is repetition — running the same code many times. That’s what loops are for, and that’s what’s next.