Transcript Patterns
Pattern Matching
The match statement
C and Java have a switch statement which uses a small integer
value to choose among alternatives
In Java 7, it is now possible to use switch with Strings
switch is rarely used in Java programs
The Scala “equivalent” is the match expression
scala> val n = 4
n: Int = 4
scala> n match {
| case 1 => "one"
| case 2 => "two"
| case _ => "many"
| }
res0: String = many
2
Matching on values
scala> object Obj
defined module Obj
scala> val d = 5.0
d: Double = 5.0
scala> val lst = List(1, 2, 3)
lst: List[Int] = List(1, 2, 3)
scala> def valMatch(x: Any) = x match {
| case 5 => println("Int")
| case 5.0 => println("Double")
| case "abc" => println("String")
| case List(1, 2, 3) => println("List")
| case Obj => println("User-defined Obj")
| case _ => println("None of the above")
| }
valMatch: (x: Any)Unit
scala> valMatch(5)
Int
scala> valMatch(Obj)
User-defined Obj
scala> valMatch("abc")
String
3
Matching on types
scala> def whatKind(x: Any) = x match {
| case s: String => s"This is the string [$s]"
| case d: Double => s"$d is a Double"
| case i: Int => s"$i is an Int"
| case x => s"I don't know what $x is"
| }
whatKind: (x: Any)String
scala> whatKind(5.0)
res3: String = 5.0 is a Double
scala> whatKind(List(1, 2, 3))
res4: String = I don't know what List(1, 2, 3) is
4
Matching with guards
scala> def oddOrEven(n: Any) = n match {
|
case n: Int if n % 2 == 0 => "Even integer"
|
case n: Int => "Odd integer"
|
case x => x + " is something else"
| }
oddOrEven: (n: Any)String
scala> oddOrEven(5)
res18: String = Odd integer
scala> oddOrEven(6)
res19: String = Even integer
scala> oddOrEven(7.0)
res20: String = 7.0 is something else
5
Matching on user-defined types
For user-defined classes, you can match on the type
scala> class Person(val name: String)
defined class Person
scala> val dave = new Person("Dave")
dave: Person = Person@234bb715
scala> dave match {
| case n: Person => "ok"
| case _ => "nope!"
| }
res2: String = ok
But you can’t match on the particular object of a plain (non-case) class
scala> dave match {
| case Person("Dave") => "ok"
| case _ => "nope!"
| }
<console>:14: error: not found: value Person
6
Matching on objects of case classes
scala> val dave = new Person("Dave")
dave: Person = Person(Dave)
scala> val beth = new Person("Beth")
beth: Person = Person(Beth)
scala>
|
|
|
sayHi:
scala> sayHi(dave)
res7: String = Oh, it's just Dave.
scala> sayHi(beth)
res8: String = Hi, Beth!
def sayHi(p: Person) = p match {
case Person("Dave") => "Oh, it's just Dave."
case Person(name) => s"Hi, $name!"
}
(p: Person)String
7
Matching on exceptions
Scala’s try-catch-finally is similar to Java’s, but the
catch clauses are case expressions
try {
val f = new FileReader("input.txt")
} catch {
case ex: FileNotFoundException => {
println("Missing file exception")
}
case ex: IOException => {
println("IO Exception")
}
} finally {
println("Exiting finally...")
}
Source: http://www.tutorialspoint.com/scala/scala_exception_handling.htm
8
Matching on optional values
The Option type is used frequently in Scala
Scala’s None is used in places where Java might use null
scala> val scores = List(78, 43, 82, 67, 55)
scores: List[Int] = List(78, 43, 82, 67, 55)
scala> scores find (_ > 90)
res0: Option[Int] = None
scala> scores find (_ < 70)
res1: Option[Int] = Some(43)
scala> (scores find (_ < 30)) match {
| case None => "Everyone is passing"
| case Some(n) => n + " isn't very good"
| }
res2: String = Everyone is passing
9
Matching in assignments
scala> val jean = new Person("Jean", 23)
jean: Person = Person(Jean,23)
scala> jean match {
| case Person(n, a) => s"$n is $a years old"
| }
res5: String = Jean is 23 years old
scala> val Person(n, a) = jean
n: String = Jean
a: Int = 23
scala> val list = List(1, 2, 3, 4, 5)
list: List[Int] = List(1, 2, 3, 4, 5)
scala> val h :: hh :: t = list
h: Int = 1
hh: Int = 2
t: List[Int] = List(3, 4, 5)
10
Matching in for expressions
scala> val capitals = Map("France" -> "Paris", "Japan" ->
"Tokyo")
capitals: scala.collection.immutable.Map[String,String] =
Map(France -> Paris, Japan -> Tokyo)
scala> for ((country, city) <- capitals) {
|
println(s"The capital of $country is $city.")
| }
The capital of France is Paris.
The capital of Japan is Tokyo.
Values that don’t match are simply filtered out
scala> val scores = List(("John", 90), ("Mary", 100), ("Bill",
95), ("Jane", 100))
scores: List[(String, Int)] = List((John,90), (Mary,100),
(Bill,95), (Jane,100))
scala> for ((name, 100) <- scores) println(name)
Mary
Jane
11
Patterns as partial functions
A sequence of cases is a partial function, and may be used
anywhere a function literal may be used
scala> val factorial: Int => Int = {
| case 0 => 1
| case n => n * factorial(n - 1)
| }
factorial: Int => Int = <function1>=
scala> factorial(5)
res14: Int = 120
scala>
|
|
|
res16:
1, 10,
(1 to 10) map {
case n if n % 2 == 0 => n / 2
case n => 3 * n + 1
}
scala.collection.immutable.IndexedSeq[Int] = Vector(4,
2, 16, 3, 22, 4, 28, 5)
12
Failing to match
It’s an error if no case in a pattern match is satisfied
There are two basic choices for the last case:
case _ will match anything, and you don’t care what
case variable will match anything, and you can use the value
of the variable in the body of the case
13
isDefinedAt
A Map is a partial function from keys to values
The method isDefinedAt determines whether a partial
function is defined for a particular input value
scala> val scores = List(("John", 90), ("Mary", 100),
("Bill", 95), ("Jane", 100))
scores: List[(String, Int)] = List((John,90), (Mary,100),
(Bill,95), (Jane,100))
scala> val mapScores = scores.toMap
mapScores: scala.collection.immutable.Map[String,Int] =
Map(John -> 90, Mary -> 100, Bill -> 95, Jane -> 100)
scala> mapScores.isDefinedAt("William")
res1: Boolean = false
scala> mapScores.isDefinedAt("Bill")
res2: Boolean = true
14
collect
collect is a partial function that takes an iterator and returns a new iterator
over only defined values
def collect[B](pf: PartialFunction[A, B]): Iterator[B]
scala> val scores = Map(("John", 90), ("Mary", 100),
("Bill", 95), ("Jane", 100))
scores: scala.collection.immutable.Map[String,Int] =
Map(John -> 90, Mary -> 100, Bill -> 95, Jane -> 100)
scala> val names = List("John", "Frank", "Jane", "Joe")
names: List[String] = List(John, Frank, Jane, Joe)
scala> names collect scores
res10: List[Int] = List(90, 100)
15
Sealed classes
A class is sealed if (1) it is declared with the keyword sealed,
and (2) all subclasses are declared on the same file
This allows Scala to check for missing cases
scala> sealed class Person // omitting responses to save space
scala> class Man extends Person
scala> class Woman extends Person
scala> class Child extends Person
scala> val p: Person = new Woman
p: Person = Woman@12efc0ee
scala> p match {
|
case m: Man => "male"
|
case f: Woman => "female"
| }
<console>:12: warning: match may not be exhaustive.
It would fail on the following inputs: Child(), Person()
p match {
^
res5: String = female
16
@ and _*
In pattern matching, val @ pattern_part captures the value
of the pattern part in the value
In matching a sequence, _* matches the remainder of the
sequence
scala> list match {
| case a @ List(b @ _, c @ _*) => s"After $b in $a comes $c"
| }
res7: String = After 1 in List(1, 2, 3, 4, 5) comes List(2, 3, 4, 5)
17
The End
18