Control Flow
## Learning Objectives
- Master if/else expressions
- Understand match expressions (Scala's switch)
- Learn for loops and comprehensions
- Work with while and do-while loops
- Understand loop control (break, continue)
## if/else Expressions
### Basic if/else
```scala
val x = 10
if (x > 0) {
println("Positive")
} else {
println("Non-positive")
}
```
### else if
```scala
def grade(score: Int): String = {
if (score >= 90) {
"A"
} else if (score >= 80) {
"B"
} else if (score >= 70) {
"C"
} else if (score >= 60) {
"D"
} else {
"F"
}
}
```
### if as Expression
In Scala, if/else returns a value:
```scala
val max = if (a > b) a else b
val sign = if (x > 0) 1 else if (x < 0) -1 else 0
```
### Assignment vs Expression
```scala
var result = ""
if (x > 0) {
result = "positive"
} else {
result = "non-positive"
}
// Equivalent (ternary-like)
val result2 = if (x > 0) "positive" else "non-positive"
```
## match Expressions
### Basic match
```scala
val day = 3
val dayName = day match {
case 1 => "Monday"
case 2 => "Tuesday"
case 3 => "Wednesday"
case 4 => "Thursday"
case 5 => "Friday"
case 6 => "Saturday"
case 7 => "Sunday"
case _ => "Invalid"
}
println(dayName) // Wednesday
```
### match as Expression
```scala
def describe(x: Any): String = x match {
case 1 => "one"
case "hello" => "greeting"
case true => "truth"
case List(1, 2, 3) => "list of three numbers"
case _ => "something else"
}
```
### Pattern Matching with Variables
```scala
def describeList(lst: List[Int]): String = lst match {
case List() => "empty list"
case head :: tail => s"non-empty list starting with $head"
case other => s"list with ${other.length} elements"
}
```
### Matching with Guards
```scala
def grade(score: Int): String = score match {
case s if s >= 90 => "A"
case s if s >= 80 => "B"
case s if s >= 70 => "C"
case s if s >= 60 => "D"
case _ => "F"
}
```
### Matching on Types
```scala
def describe(obj: Any): String = obj match {
case i: Int if i > 0 => s"positive integer: $i"
case s: String => s"string: $s"
case l: List[_] => s"list of length ${l.length}"
case _: BigInt => "a big integer"
case null => "null"
case _ => "something unknown"
}
```
## for Loops
### Basic for Loop
```scala
for (i <- 1 to 5) {
println(i)
}
// Prints: 1, 2, 3, 4, 5
```
### until vs to
```scala
for (i <- 0 until 5) {
println(i)
}
// Prints: 0, 1, 2, 3, 4
for (i <- 1 to 5) {
println(i)
}
// Prints: 1, 2, 3, 4, 5
```
### Iterating Collections
```scala
val fruits = List("apple", "banana", "cherry")
for (fruit <- fruits) {
println(fruit)
}
// With index
for (i <- fruits.indices) {
println(s"$i: ${fruits(i)}")
}
```
### Multiple Generators
```scala
for (i <- 1 to 3; j <- 1 to 3) {
println(s"($i, $j)")
}
// With guard
for (i <- 1 to 5; j <- 1 to i) {
println(s"$i >= $j")
}
```
### for with Guards
```scala
for (i <- 1 to 100 if i % 3 == 0 if i % 5 == 0) {
println(s"FizzBuzz: $i")
}
// Same as
for (i <- 1 to 100 if i % 15 == 0) {
println(s"FizzBuzz: $i")
}
```
## for Comprehensions
### yield
```scala
val squares = for (i <- 1 to 5) yield i * i
// List(1, 4, 9, 16, 25)
val doubled = for (i <- List(1, 2, 3)) yield i * 2
// List(2, 4, 6)
```
### Transforming Collections
```scala
case class Person(name: String, age: Int)
val people = List(
Person("Alice", 30),
Person("Bob", 25),
Person("Charlie", 35)
)
val names = for (p <- people) yield p.name
// List("Alice", "Bob", "Charlie")
val adults = for (p <- people if p.age >= 30) yield p
// List(Person("Alice", 30), Person("Charlie", 35))
```
### Nested Comprehensions
```scala
val matrix = List(
List(1, 2, 3),
List(4, 5, 6),
List(7, 8, 9)
)
val flattened = for {
row <- matrix
element <- row if element % 2 == 0
} yield element
// List(2, 4, 6, 8)
```
## while Loops
### while Loop
```scala
var i = 0
while (i < 5) {
println(i)
i += 1
}
```
### do-while Loop
```scala
var j = 0
do {
println(j)
j += 1
} while (j < 5)
```
## Loop Control
### break (Scala 2.10+)
```scala
import scala.util.control.Breaks._
breakable {
for (i <- 1 to 100) {
if (i == 10) break
println(i)
}
}
```
### continue
Scala doesn't have continue. Use guards instead:
```scala
for (i <- 1 to 10) {
if (i % 2 == 0) {
// Process even numbers
println(s"Even: $i")
}
// Odd numbers are skipped
}
```
## Return Values
### Return from Functions
```scala
def findFirst[T](arr: List[T], predicate: T => Boolean): Option[T] = {
for (elem <- arr) {
if (predicate(elem)) return Some(elem)
}
None
}
```
### Labeled Returns
```scala
def hasEvenNumber(list: List[Int]): Boolean = {
list.foreach { num =>
if (num % 2 == 0) return true
}
false
}
```
## Summary
- `if/else` is an expression that returns a value
- `match` is Scala's powerful pattern matching construct
- `for` loops can iterate over ranges, collections, and multiple generators
- `yield` transforms results in for comprehensions
- Guards (`if`) filter iterations
- `while` and `do-while` are available for imperative code
- Use `breakable` from `scala.util.control.Breaks` for break functionality
- Prefer functional approaches (comprehensions) over imperative loops when possible
Comments
Comments powered by Giscus
To enable comments, add your Giscus embed code here.
Learn more about Giscus →