Skip to content

Commit 3a77c62

Browse files
author
Ye Chen
committed
tmp
1 parent f0845ae commit 3a77c62

File tree

1 file changed

+137
-1
lines changed

1 file changed

+137
-1
lines changed

_zh-cn/tour/pattern-matching.md

Lines changed: 137 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
layout: tour
3-
title: Pattern Matching
3+
title: 模式匹配
44

55
discourse: false
66

@@ -13,3 +13,139 @@ language: zh-cn
1313
next-page: singleton-objects
1414
previous-page: case-classes
1515
---
16+
17+
模式匹配是检查某个值(value)是否匹配某一个模式的机制,一个成功的匹配同时会将匹配值解构为其组成部分。它是Java中的`switch`语句的升级版,同样可以用于替代一些列的 if/else 语句。
18+
19+
## 语法
20+
一个模式匹配语句包括一个待匹配的值,`match`关键字,以及至少一个`case`语句。
21+
22+
```tut
23+
import scala.util.Random
24+
25+
val x: Int = Random.nextInt(10)
26+
27+
x match {
28+
case 0 => "zero"
29+
case 1 => "one"
30+
case 2 => "two"
31+
case _ => "many"
32+
}
33+
```
34+
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_.
35+
36+
Match expressions have a value.
37+
```tut
38+
def matchTest(x: Int): String = x match {
39+
case 1 => "one"
40+
case 2 => "two"
41+
case _ => "many"
42+
}
43+
matchTest(3) // many
44+
matchTest(1) // one
45+
```
46+
This match expression has a type String because all of the cases return String. Therefore, the function `matchTest` returns a String.
47+
48+
## Matching on case classes
49+
50+
Case classes are especially useful for pattern matching.
51+
52+
```tut
53+
abstract class Notification
54+
55+
case class Email(sender: String, title: String, body: String) extends Notification
56+
57+
case class SMS(caller: String, message: String) extends Notification
58+
59+
case class VoiceRecording(contactName: String, link: String) extends Notification
60+
61+
62+
```
63+
`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:
64+
65+
```
66+
def showNotification(notification: Notification): String = {
67+
notification match {
68+
case Email(email, title, _) =>
69+
s"You got an email from $email with title: $title"
70+
case SMS(number, message) =>
71+
s"You got an SMS from $number! Message: $message"
72+
case VoiceRecording(name, link) =>
73+
s"you received a Voice Recording from $name! Click the link to hear it: $link"
74+
}
75+
}
76+
val someSms = SMS("12345", "Are you there?")
77+
val someVoiceRecording = VoiceRecording("Tom", "voicerecording.org/id/123")
78+
79+
println(showNotification(someSms)) // prints You got an SMS from 12345! Message: Are you there?
80+
81+
println(showNotification(someVoiceRecording)) // you received a Voice Recording from Tom! Click the link to hear it: voicerecording.org/id/123
82+
```
83+
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 `_`.
84+
85+
## Pattern guards
86+
Pattern guards are simply boolean expressions which are used to make cases more specific. Just add `if <boolean expression>` after the pattern.
87+
```
88+
89+
def showImportantNotification(notification: Notification, importantPeopleInfo: Seq[String]): String = {
90+
notification match {
91+
case Email(email, _, _) if importantPeopleInfo.contains(email) =>
92+
"You got an email from special someone!"
93+
case SMS(number, _) if importantPeopleInfo.contains(number) =>
94+
"You got an SMS from special someone!"
95+
case other =>
96+
showNotification(other) // nothing special, delegate to our original showNotification function
97+
}
98+
}
99+
100+
val importantPeopleInfo = Seq("867-5309", "[email protected]")
101+
102+
val someSms = SMS("867-5309", "Are you there?")
103+
val someVoiceRecording = VoiceRecording("Tom", "voicerecording.org/id/123")
104+
val importantEmail = Email("[email protected]", "Drinks tonight?", "I'm free after 5!")
105+
val importantSms = SMS("867-5309", "I'm here! Where are you?")
106+
107+
println(showImportantNotification(someSms, importantPeopleInfo))
108+
println(showImportantNotification(someVoiceRecording, importantPeopleInfo))
109+
println(showImportantNotification(importantEmail, importantPeopleInfo))
110+
println(showImportantNotification(importantSms, importantPeopleInfo))
111+
```
112+
113+
In the `case Email(email, _, _) if importantPeopleInfo.contains(email)`, the pattern is matched only if the `email` is in the list of important people.
114+
115+
## Matching on type only
116+
You can match on the type like so:
117+
```tut
118+
abstract class Device
119+
case class Phone(model: String) extends Device{
120+
def screenOff = "Turning screen off"
121+
}
122+
case class Computer(model: String) extends Device {
123+
def screenSaverOn = "Turning screen saver on..."
124+
}
125+
126+
def goIdle(device: Device) = device match {
127+
case p: Phone => p.screenOff
128+
case c: Computer => c.screenSaverOn
129+
}
130+
```
131+
`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).
132+
133+
## Sealed classes
134+
Traits and classes can be marked `sealed` which means all subtypes must be declared in the same file. This assures that all subtypes are known.
135+
136+
```tut
137+
sealed abstract class Furniture
138+
case class Couch() extends Furniture
139+
case class Chair() extends Furniture
140+
141+
def findPlaceToSit(piece: Furniture): String = piece match {
142+
case a: Couch => "Lie on the couch"
143+
case b: Chair => "Sit on the chair"
144+
}
145+
```
146+
This is useful for pattern matching because we don't need a "catch all" case.
147+
148+
## Notes
149+
150+
Scala's pattern matching statement is most useful for matching on algebraic types expressed via [case classes](case-classes.html).
151+
Scala also allows the definition of patterns independently of case classes, using `unapply` methods in [extractor objects](extractor-objects.html).

0 commit comments

Comments
 (0)