You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Scala has a built-in general pattern matching mechanism. It allows to match on any sort of data with a first-match policy.
16
-
Here is a small example which shows how to match against an integer value:
16
+
Pattern matching is a mechanism for checking a value against a pattern. A successful match can also deconstruct a value into its constituent parts. It is a more powerful version of the `switch` statement in Java and it can likewise be used in place of a series of if/else statements.
17
17
18
+
## Syntax
19
+
A match expression has a value, the `match` keyword, and at least one `case` clause.
18
20
```tut
19
-
object MatchTest1 extends App {
20
-
def matchTest(x: Int): String = x match {
21
-
case 1 => "one"
22
-
case 2 => "two"
23
-
case _ => "many"
24
-
}
25
-
println(matchTest(3))
21
+
import scala.util.Random
22
+
23
+
val x: Int = Random.nextInt(10)
24
+
25
+
x match {
26
+
case 0 => "zero"
27
+
case 1 => "one"
28
+
case 2 => "two"
29
+
case _ => "many"
30
+
}
31
+
```
32
+
The `val x` above is a random integer between 0 and 10. `x` becomes the left operand of the `match` operator and on the right is an expression with four cases. The last case `_` is a "catch all" case for any number greater than 2. Cases are also called _alternatives_.
33
+
34
+
Match expressions have a value.
35
+
```tut
36
+
def matchTest(x: Int): String = x match {
37
+
case 1 => "one"
38
+
case 2 => "two"
39
+
case _ => "many"
26
40
}
41
+
matchTest(3) // many
42
+
matchTest(1) // one
27
43
```
44
+
This match expression has a type String because all of the cases return String. Therefore, the function `matchTest` returns a String.
28
45
29
-
The block with the `case` statements defines a function which maps integers to strings. The `match` keyword provides a convenient way of applying a function (like the pattern matching function above) to an object.
46
+
## Matching on case classes
30
47
31
-
Here is a second example which matches a value against patterns of different types:
48
+
Case classes are especially useful for pattern matching.
32
49
33
50
```tut
34
-
object MatchTest2 extends App {
35
-
def matchTest(x: Any): Any = x match {
36
-
case 1 => "one"
37
-
case "two" => 2
38
-
case y: Int => "scala.Int"
51
+
abstract class Notification
52
+
53
+
case class Email(sender: String, title: String, body: String) extends Notification
54
+
55
+
case class SMS(caller: String, message: String) extends Notification
56
+
57
+
case class VoiceRecording(contactName: String, link: String) extends Notification
58
+
59
+
60
+
```
61
+
`Notification` is an abstract super class which has three concrete Notification types implemented with case classes `Email`, `SMS`, and `VoiceRecording`. Now we can do pattern matching on these case classes:
s"You got an email from $email with title: $title"
68
+
case SMS(number, message) =>
69
+
s"You got an SMS from $number! Message: $message"
70
+
case VoiceRecording(name, link) =>
71
+
s"you received a Voice Recording from $name! Click the link to hear it: $link"
72
+
}
73
+
}
74
+
val someSms = SMS("12345", "Are you there?")
75
+
val someVoiceRecording = VoiceRecording("Tom", "voicerecording.org/id/123")
76
+
77
+
println(showNotification(someSms)) // prints You got an SMS from 12345! Message: Are you there?
78
+
79
+
println(showNotification(someVoiceRecording)) // you received a Voice Recording from Tom! Click the link to hear it: voicerecording.org/id/123
80
+
```
81
+
The function `showNotification` takes as a parameter the abstract type `Notification` and matches on the type of `Notification` (i.e. it figures out whether it's an `Email`, `SMS`, or `VoiceRecording`). In the `case Email(email, title, _)` the fields `email` and `title` are used in the return value but the `body` field is ignored with `_`.
82
+
83
+
## Pattern guards
84
+
Pattern guards are simply boolean expressions which are used to make cases more specific. Just add `if <boolean expression>` after the pattern.
In the `case Email(email, _, _) if importantPeopleInfo.contains(email)`, the pattern is matched only if the `email` is in the list of important people.
112
+
113
+
## Matching on type only
114
+
You can match on the type like so:
115
+
```tut
116
+
abstract class Device
117
+
case class Phone(model: String) extends Device{
118
+
def screenOff = "Turning screen off"
119
+
}
120
+
case class Computer(model: String) extends Device {
121
+
def screenSaverOn = "Turning screen saver on..."
122
+
}
123
+
124
+
def goIdle(device: Device) = device match {
125
+
case p: Phone => p.screenOff
126
+
case c: Computer => c.screenSaverOn
127
+
}
128
+
```
129
+
`def goIdle` has a different behavior depending on the type of `Device`. This is useful when the case needs to call a method on the pattern. It is a convention to use the first letter of the type as the case identifier (`p` and `c` in this case).
130
+
131
+
## Sealed classes
132
+
Traits and classes can be marked `sealed` which means all subtypes must be declared in the same file. The assures that all subtypes are known.
133
+
134
+
```tut
135
+
sealed abstract class Furniture
136
+
case class Couch() extends Furniture
137
+
case class Chair() extends Furniture
138
+
139
+
def findPlaceToSit(piece: Furniture): String = piece match {
140
+
case a: Couch => "Lie on the couch"
141
+
case b: Chair => "Sit on the chair"
41
142
}
42
143
```
144
+
This is useful for pattern matching because we don't need a "catch all" case.
43
145
44
-
The first `case` matches if `x` refers to the integer value `1`. The second `case` matches if `x` is equal to the string `"two"`. The third case consists of a typed pattern; it matches against any integer and binds the selector value `x` to the variable `y` of type integer.
146
+
## Notes
45
147
46
148
Scala's pattern matching statement is most useful for matching on algebraic types expressed via [case classes](case-classes.html).
47
149
Scala also allows the definition of patterns independently of case classes, using `unapply` methods in [extractor objects](extractor-objects.html).
0 commit comments