A block is a sequence of semi-colon-separated expressions surrounded by curly braces. For example, a block might be the body of a function:
def square10(n: Int) = {val x = 10; def square(x: Double) = x * x; square(x + n)}
scala> square10(3)
res23: Double = 169.0
The scope of all declarations inside of a block extends to the end of the block. In the example above square and x disappear as soon as the block terminates:
scala> square(x)
<console>:8: error: not found: value square
square(x)
^
<console>:8: error: not found: value x
square(x)
^
A block is an expression. Its value is the value of its last sub-expression:
scala> val
n = {1; 2; 3; 4; 5}
// lots of
warnings
scala> n
5
Semicolons aren't necessary for multi-line blocks:
def square10(n: Int) = {
val x = 10
def square(x:
Double) = x * x
square(x + n)
}
Beginning with Scala 3.0 curly braces aren't needed for a block that's the body of a function or nested in another control structure. Instead indentation tells the parser the scope of the expression:
def square10(n: Int) =
val x = 10
def square(x:
Double) = x * x
square(x + n)
Scala conditional expressions are similar to Java's x?y:z expressions:
scala> def max(x:
Int, y: Int) = if x > y then x else y
max: (x: Int, y: Int)Int
scala> max(2, 3)
res26: Int = 3
Here's the equivalent Java version:
Integer max(Integer x, Integer y) {
return (x > y)? x: y;
}
Note: Scala 2 syntax doesn't use the keyword "then". Instead the condition is surrounded by parentheses:
def max(x: Int, y: Int) = if (x > y) x else y
Scala's match expression is a
powerful improvement to Java's switch statement.
Format:
key match {
case guard1 => branch1
case guard2 => branch2
case guard3 => branch3
// etc
case _ => default
}
Note that the curly braces are optional in Scala 3.0.
var
day = 3
day match
case 0 => println("Sunday")
case 1 => println("Monday")
case 2 => println("Tueaday")
case 3 => println("Wednesday")
case 4 => println("Thursday")
case 5 => println("Friday")
case 6 => println("Saturday")
case _ => throw Exception("Invalid
day")
day
match
case 0 | 6 => println("Weekend")
case 1 | 2 | 3 | 4 | 5 => println("Weekday")
Assume Rectangle and Circle are subclasses of Shape where Rectangle has a perimeter method and Circle has a circumference method:
abstract class Shape
class Circle extends Shape:
var radius = 10.0
def circumference = 2 * math.Pi * radius
class Rectangle extends Shape:
var height = 10.0
var length = 10.0
def perimeter = 2 * height + 2 *
length
We can define a general function for computing the border length of a shape as follows:
object shapeDemo extends App {
def borderLength(s: Shape) =
s match
case r: Rectangle => r.perimeter
case c: Circle => c.circumference
case _ => 0.0
println(boundaryLength(Circle())) // prints 62.83185307179586
println(boundaryLength(Rectangle())) // prints 40.0
}
The equivalent in Java might look like this:
Double borderLength(Shape s) {
if (s instanceof
Rectangle) return ((Rectangle)s).perimeter();
if (s instanceof
Circle) return ((Circle)s).circumference();
return 0
}
Notice that in the Java version we must perform safe casts, but Scala's match expression does this for us.
Of course match/case can be used on ordinary conditions, although the syntax is a bit wonky:
income match
case income if income < 100 => .1 *
income
case income if income < 1000 => .2 *
income
case income if income < 10000 => .3 *
income
case _ => .5 * income
We can use a regular expression
to extract matching elements from a string. (More on this later.)
val expPattern = """([0-9]+)\s*(\+|\*|-|/)\s*([0-9]+)""".r
def eval(exp: String)
=
exp match {
case expPattern(arg1, "+", arg2)
=> arg1.toInt + arg2.toInt
case expPattern(arg1, "-", arg2)
=> arg1.toInt - arg2.toInt
case expPattern(arg1, "*", arg2)
=> arg1.toInt * arg2.toInt
case expPattern(arg1, "/", arg2)
=> arg1.toInt / arg2.toInt
case _ => throw Exception("Invalid
expression")
}
Scala has the same while and do loops as Java:
while (condition)
expression
do expression while
(condition)
The for loop is like Java's enhanced for loop in that it iterates over collections. The simplest type of collection is called a range.
Here are a few examples:
scala> for (i
<- 0 to 9) print(i)
0123456789
scala> for (i <- 0
until 9) print(i)
012345678
One for-loop can iterate over multiple ranges simultaneously:
scala> for(i <- 0 to 3; j <- 0 to 3) println(i + j)
0
1
2
3
1
2
3
4
2
3
4
5
3
4
5
6
The for loop can have multiple generators and guards:
scala> for(i <- 0 to 15 if i % 3 == 0) print(" " + i)
0 3 6 9 12 15
scala> for(i
<- 0 until 5; j <- 0 until 5 if i != j) { println("" + i + "
+ " + j + " = " + (i + j)); }
0 + 1 = 1
0 + 2 = 2
0 + 3 = 3
0 + 4 = 4
1 + 0 = 1
1 + 2 = 3
1 + 3 = 4
1 + 4 = 5
2 + 0 = 2
2 + 1 = 3
2 + 3 = 5
2 + 4 = 6
3 + 0 = 3
3 + 1 = 4
3 + 2 = 5
3 + 4 = 7
4 + 0 = 4
4 + 1 = 5
4 + 2 = 6
4 + 3 = 7
For-loops can iterate over other types of collections:
scala> val
greeting = "bon jour"
greeting: String = bon jour
scala> for(c <-
greeting) print(c)
bon jour
Of course this works, too:
cala> for(i <- 0 until greeting.length)
print(greeting(i))
bon jour
Comprehension can collect the values of each iteration into a collection:
scala> for(i <- 2 until 10) yield 3 * i +
2
res3: = Vector(8, 11, 14, 17, 20, 23, 26, 29)