1、模式匹配
模式匹配是一种根据模式检查值的机制。它是switch(
Java中语句)的更强大版本,它同样可以用来代替一系列if / else语句。
- 句法
匹配表达式具有值,match
关键字和至少一个case
子句。
import scala.util.Random val x: Int = Random.nextInt(10) x match { case 0 => "zero" case 1 => "one" case 2 => "two" case _ => "other" }
val x
上面是0和10之间的随机整数,x
成为的左操作数match
运算符和右边是与4箱子的表达式。最后一种情况(_)
是任何其他可能Int
值的“全部捕获”情况。案件也被称为替代品。
- 匹配案例类
案例类对模式匹配特别有用。
abstract class Notification//抽象超类 case class Email(sender: String, title: String, body: String) extends Notification case class SMS(caller: String, message: String) extends Notification case class VoiceRecording(contactName: String, link: String) extends Notification
Notification
是具有与壳体的类实现的三个具体的通知类型的抽象超类Email
,SMS
和VoiceRecording
。现在我们可以对这些案例类进行模式匹配:
def showNotification(notification: Notification): String = { notification match { case Email(sender, title, _) => s"You got an email from $sender with title: $title" case SMS(number, message) => s"You got an SMS from $number! Message: $message" case VoiceRecording(name, link) => s"you received a Voice Recording from $name! Click the link to hear it: $link" } } val someSms = SMS("12345", "Are you there?") val someVoiceRecording = VoiceRecording("Tom", "voicerecording.org/id/123") println(showNotification(someSmps)) println(showNotification(someVoiceRecording))
该函数showNotification
作为参数的抽象类型Notification
和类型相匹配Notification
(即,它计算出它是否是一个Email
,SMS
或VoiceRecording
)。在case Email(sender, title, _)
字段中sender
并且title
在返回值中使用但是body
忽略该字段_
。
- 模式守护
模式保护只是布尔表达式,用于使案例更具体。只需if <boolean expression>
在模式后添加。
def showImportantNotification(notification: Notification, importantPeopleInfo: Seq[String]): String = { notification match { case Email(sender, _, _) if importantPeopleInfo.contains(sender) => "You got an email from special someone!" case SMS(number, _) if importantPeopleInfo.contains(number) => "You got an SMS from special someone!" case other => showNotification(other) } } val importantPeopleInfo = Seq("867-5309", "jenny@gmail.com") val someSms = SMS("867-5309", "Are you there?") val someVoiceRecording = VoiceRecording("Tom", "voicerecording.org/id/123") val importantEmail = Email("jenny@gmail.com", "Drinks tonight?", "I'm free after 5!") val importantSms = SMS("867-5309", "I'm here! Where are you?") println(showImportantNotification(someSms, importantPeopleInfo)) println(showImportantNotification(someVoiceRecording, importantPeopleInfo)) println(showImportantNotification(importantEmail, importantPeopleInfo)) println(showImportantNotification(importantSms, importantPeopleInfo))
在图中case Email(sender, _, _) if importantPeopleInfo.contains(sender)
,只有sender
在重要人物列表中才匹配模式。
- 仅在类型上匹配
abstract class Device case class Phone(model: String) extends Device{ def screenOff = "Turning screen off" } case class Computer(model: String) extends Device { def screenSaverOn = "Turning screen saver on..." } def goIdle(device: Device) = device match { case p: Phone => p.screenOff case c: Computer => c.screenSaverOn }
def goIdle
具有不同的行为取决于类型Device
。当案例需要在模式上调用方法时,这很有用。它是使用类型的情况下标识(第一个字母的公约p
和c
在这种情况下)。
- 密封课程
可以标记特征和类sealed
,这意味着必须在同一文件中声明所有子类型。这确保了所有亚型都是已知的。
sealed abstract class Furniture case class Couch() extends Furniture case class Chair() extends Furniture def findPlaceToSit(piece: Furniture): String = piece match { case a: Couch => "Lie on the couch" case b: Chair => "Sit on the chair" }
2、案例类
- 定义案例类
最小的案例类需要关键字case class
,标识符和参数列表(可能为空):
case class Book(isbn: String) val frankenstein = Book("912-0111182114")
注意:实例化Book
案例时没有new关键字。这是因为case类apply
默认有一个方法来处理对象构造。
使用参数创建案例类时,参数是公共val
的。
case class Message(sender: String, recipient: String, body: String) val message1 = Message("guillaume@quebec.ca", "jorge@catalonia.es", "Ça va ?") println(message1.sender) //合法的 message1.sender = "travis@washington.us" // 不合法的
不能重新分配,message1.sender
因为它是一个val
(即不可变的)。