Conditional Logic
Overview
Go provides if/else statements and switch statements for conditional logic. Both are straightforward but have unique features compared to other languages.
The if Statement
Basic Syntax
if condition {
// code
}With else
if x > 0 {
fmt.Println("Positive")
} else {
fmt.Println("Non-positive")
}With else if
if x > 0 {
fmt.Println("Positive")
} else if x < 0 {
fmt.Println("Negative")
} else {
fmt.Println("Zero")
}Initialization Statement
Go allows a statement before the condition:
if err := doSomething(); err != nil {
// Handle error
// err is only visible in this if/else block
return err
}
// err is not accessible hereThis is idiomatic for error handling:
if file, err := os.Open("data.txt"); err != nil {
log.Fatal(err)
} else {
defer file.Close()
// Use file
}No Parentheses Required
Unlike C-style languages, conditions don’t need parentheses:
// Go style
if x > 0 {
}
// Not idiomatic (but valid)
if (x > 0) {
}Braces Required
Braces are mandatory, even for single statements:
// Error: missing braces
if x > 0
fmt.Println("yes")
// Correct
if x > 0 {
fmt.Println("yes")
}Boolean Expressions
Comparison Operators
| Operator | Meaning |
|---|---|
== |
Equal |
!= |
Not equal |
< |
Less than |
> |
Greater than |
<= |
Less than or equal |
>= |
Greater than or equal |
Logical Operators
| Operator | Meaning |
|---|---|
&& |
AND (short-circuit) |
|| |
OR (short-circuit) |
! |
NOT |
// Short-circuit evaluation
if x != 0 && y/x > 1 {
// y/x only evaluated if x != 0
}
if ptr != nil && ptr.Value > 0 {
// Ptr.Value only accessed if ptr != nil
}The switch Statement
Basic Switch
switch day {
case "Monday":
fmt.Println("Start of week")
case "Friday":
fmt.Println("Almost weekend!")
case "Saturday", "Sunday":
fmt.Println("Weekend!")
default:
fmt.Println("Midweek")
}No Fall-Through by Default
Unlike C, cases don’t fall through:
switch n {
case 1:
fmt.Println("One")
// No break needed, stops here
case 2:
fmt.Println("Two")
}Explicit Fallthrough
Use fallthrough keyword when needed:
switch n {
case 1:
fmt.Println("One")
fallthrough
case 2:
fmt.Println("Two")
}
// Input: 1
// Output:
// One
// TwoSwitch with Initialization
switch os := runtime.GOOS; os {
case "darwin":
fmt.Println("macOS")
case "linux":
fmt.Println("Linux")
default:
fmt.Println(os)
}Expression-less Switch
A switch without an expression is equivalent to switch true:
t := time.Now()
switch {
case t.Hour() < 12:
fmt.Println("Good morning!")
case t.Hour() < 17:
fmt.Println("Good afternoon!")
default:
fmt.Println("Good evening!")
}This is often cleaner than chained if/else if:
switch {
case x < 0:
return "negative"
case x == 0:
return "zero"
case x > 0:
return "positive"
}Type Switch
Special form for interface type assertions:
func describe(i interface{}) {
switch v := i.(type) {
case int:
fmt.Printf("Integer: %d\n", v)
case string:
fmt.Printf("String: %s\n", v)
case bool:
fmt.Printf("Boolean: %t\n", v)
default:
fmt.Printf("Unknown type: %T\n", v)
}
}
describe(42) // Integer: 42
describe("hello") // String: hello
describe(true) // Boolean: true
describe(3.14) // Unknown type: float64Common Patterns
Error Checking
result, err := someOperation()
if err != nil {
return fmt.Errorf("operation failed: %w", err)
}
// Use resultBoolean Assignment
var status string
if success {
status = "completed"
} else {
status = "failed"
}
// Note: Go doesn't have a ternary operator
// This doesn't work: status := success ? "completed" : "failed"Guard Clauses
func processUser(user *User) error {
if user == nil {
return errors.New("user cannot be nil")
}
if user.Name == "" {
return errors.New("user name required")
}
if user.Age < 0 {
return errors.New("invalid age")
}
// Main logic here
return nil
}ok-idiom
// Map lookup
if val, ok := myMap[key]; ok {
fmt.Println("Found:", val)
} else {
fmt.Println("Not found")
}
// Type assertion
if str, ok := value.(string); ok {
fmt.Println("String:", str)
}
// Channel receive
if val, ok := <-ch; ok {
fmt.Println("Received:", val)
} else {
fmt.Println("Channel closed")
}Comma-ok Pattern
// Check map existence
if _, exists := users[id]; exists {
// User exists
}
// Check channel state
if _, open := <-ch; !open {
// Channel is closed
}Switch vs If/Else
Prefer Switch When:
// Multiple discrete values
switch status {
case "pending", "processing":
queue()
case "done":
complete()
case "error":
retry()
}Prefer If/Else When:
// Complex conditions
if x > 0 && y > 0 && x*y < 100 {
// ...
} else if x < 0 || y < 0 {
// ...
}Summary
| Feature | Description |
|---|---|
if |
Basic conditional |
if x := val; condition |
If with initialization |
switch expr |
Multi-way branching |
switch { case cond: } |
Expression-less switch |
switch v := x.(type) |
Type switch |
fallthrough |
Explicit fall-through in switch |