Pattern Matching Basics
FILE : PatternMatching1Demo
At first pattern matching in scala looks like simple switch. You can create a variable and trigger an action according to its value
someValue match {
case 1 => println("matched 1")
case other => println(s"matched $other")
}
The real power of this mechanism is shown when we use case classes - then we can easily decompose those values to handle properly each case.
case class SimpleCaseClass(innerValue:String)
simpleExample match {
case SimpleCaseClass(innerValue) => println(s"inner value is : $innerValue")
case _ => println("can not extract inner value")
}
This mechanism becomes more useful in case of complex case classes which contains other case classes
case class ComplexCaseClass(value:String, innerCaseClass:SimpleCaseClass)
val complex=ComplexCaseClass("complex",SimpleCaseClass("simple"))
complex match {
case ComplexCaseClass(name,SimpleCaseClass(inner)) =>
println(s"complex case class has : name=$name , with inner value=$inner")
}
Information Hiding
At first it seems that we are breaking encapsulation with pattern matching. First of all _case classes have different _philosophy than standard classes which we could see in java. We don't want to protect access to mutable data because... there is no mutable data at all!
But what if we want to have some private state for performance reason or something like that? Then we can create custom deconstructors - more on this mechanism in next workshops.
Patterns everywhere
You don't need match...case syntax to use convenience of Pattern Matching in the code.
You can use it during assignment :
val ComplexCaseClass(extractedName,SimpleCaseClass(extractedInner)) = complex
val tuple:(Int,String) = (1,"aaa")
val (key,value) = tuple
Guards
This simple concept allows you to add conditions to given case pattern
anotherValue match {
case s:String if s.length < 3 => println(s" very short string $s")
case s:String => println(s" long string $s")
case i:Int if i > 0 => println("positive integer $i")
case i:Int if i < 0 => println("negative integer $i")
case i:Int => println("this must be zero : $i")
case other => println(s"neither String nor Integer : $other")
Performance
If you are matching primitives then generated bytecode may use standard java switch bytecode
To give a hint from compiler if this is doable you need to use @switch annotation
import scala.annotation.switch
(i: @switch) match {
case 9 => println("9")
//uncomment to check warning
// case SimpleCaseClass(value) => println(s"value from simple case class = $value")
case _ => println("other")
}
Exercises
FILE: PatternMatching1Exercises
Exercise1 Finish implementation of simple calculator which matches on two case classes Multiply _or _Add and then performs proper mathematical operation.
Exercise2 You need to properly identify type of passed variable
Exercise3
Here you need to pattern match on complex case classes representing expressions