本文主要是介绍Scala 入门-模式匹配,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
专栏原创出处:github-源笔记文件 ,github-源码 ,欢迎 Star,转载请附上原文出处链接和本声明。
Scala 编程语言专栏系列笔记,系统性学习可访问个人复盘笔记-技术博客 Scala 编程语言
什么是模式匹配
模式匹配用来检查某一个值是否适用于定义好的一个固定模式,匹配成功可以解构出该值的所有组成元素。
模式匹配是 Java 中的 switch 语句的升级版,同样可以用于替代一系列的 if/else 语句。
-
「案例类」 非常适用于模式匹配,具体内容可以参考《案例类》。
-
可以利用「提取器对象」中的
unapply
方法来定义非案例类对象的匹配。
语法
一个模式匹配语句包括一个待匹配的值,match
关键字,以及至少一个在 {}
中包含的 case
语句。
import scala.util.Randomval x: Int = Random.nextInt(10)// 具体值的模式匹配x match {case 0 => "zero"case 1 => "one"case 2 => "two"case _ => "other" // 表示匹配其余所有情况,在这里就是其他可能的整型值。}// match 表达式是有返回值的,因为所有的情况均返回 string,所以 matchTest 函数的返回值类型是 stringdef matchTest(x: Int): String = x match {case 1 => "one"case 2 => "two"case _ => "other"}
匹配类型
案例类的模式匹配
Scala 会为案例类自动创建伴生对象,而伴生对象中定义了 unapply
方法。
因此案例类很适合用于模式匹配,可以通过模式匹配获取成员属性。
abstract class Notificationcase class Email(sender: String, title: String, body: String) extends Notificationcase class SMS(caller: String, message: String) extends Notificationcase class VoiceRecording(contactName: String, link: String) extends Notificationdef showNotification(notification: Notification): String = {notification match {// 对象的 sender 和 title 属性在返回值中被使用,而 body 属性则被忽略,故使用 _ 占位符代替。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(someSms))// You got an SMS from 12345! Message: Are you there?println(showNotification(someVoiceRecording))// you received a Voice Recording from Tom! Click the link to hear it: voicerecording.org/id/123
模式守卫
为了让匹配更加具体,可以使用模式守卫,也就是在模式后面加上 if (boolean expression)
。
abstract class Notificationcase class Email(sender: String, title: String, body: String) extends Notificationcase class SMS(caller: String, message: String) extends Notificationcase class VoiceRecording(contactName: String, link: String) extends Notificationdef show(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"}}def importantShow(notification: Notification, important: Seq[String]): String = {notification match {// 此处定义的模式匹配为守卫模式,匹配成功之后还需要进行 if 判断// 只有是 Email 类型,并且 important 集合中存在 sender 属性才可以匹配成功case Email(sender, _, _) if important.contains(sender) =>"You got an email from special someone!"case SMS(number, _) if important.contains(number) =>"You got an SMS from special someone!"case other =>// nothing special, delegate to our original show functionshow(other)}}val important = Seq("867-5309", "jenny@gmail.com")val sms = SMS("867-5309", "Are you there?")val sms2 = SMS("867-5111", "I'm here! Where are you?")val voice = VoiceRecording("Tom", "voicerecording.org/id/123")println(importantShow(sms, important))// You got an SMS from special someone!println(importantShow(sms2, important))// You got an SMS from 867-5111! Message: I'm here! Where are you?println(importantShow(voice, important))// you received a Voice Recording from Tom! Click the link to hear it: voicerecording.org/id/123
仅匹配类型
本模式匹配适用于不同类型的对象需要调用不同的方法的情况。
一般使用类型的首字母作为 case
的标识符。
{abstract class Devicecase class Phone(model: String) extends Device {def screenOff = "Turning screen off"}case class Computer(model: String) extends Device {def screenSaverOn = "Turning screen saver on..."}// goIdle 函数对不同类型的 Device 有着不同的表现,采用类型的首字母作为 case 的标识符:p、cdef goIdle(device: Device) = device match {case p: Phone => p.screenOffcase c: Computer => c.screenSaverOn}
}
中缀表达式的模式匹配
中缀表达式是一个算数
或逻辑公式
的表示方法,将 操作符
置于 操作数
的中间。
// 例如 :: 是 scala.collection.immutable.List 中定义的一个方法// def ::[B >: A] (x: B): List[B] = new scala.collection.immutable.::(x, this)1 :: List(2, 3) = List(2, 3).::(1) = List(1, 2, 3)// 中缀表达式用于模式匹配List(1,2,3,4,5) match {// first 为第一个元素,second 为第二个元素,tail 为剩余元素// 即 List(1,2,3,4,5) = 1 :: 2 :: List(3,4,5)case first :: second :: tail => println(tail)}// List(3, 4, 5)
什么是密封类
「特质」 和 「类」 可以用 sealed
标记为密封的,被标记后其所有子类必须与它存在于相同的文件中,从而保证所有子类型都是已知的。
用于模式匹配,当抽象类加了 sealed
之后,scala 在编译的时候会进行检查,如果有漏掉的 case
类型,会警告提示。
// Couch 和 Chair 必须和 Furniture 定义在相同的文件中sealed abstract class Furniturecase class Couch() extends Furniturecase class Chair() extends Furniture// 由于 Man 加了 sealed 关键字,模式匹配时,scala 会检测是否遗漏匹配的类型,编译时会警告提醒sealed abstract class Mancase object American extends Mancase object Chinese extends Mancase object Russia extends Mandef from(m: Man) = m match {case American ⇒ println("American")case Chinese ⇒ println("Chinese")}// Warning:(61, 29) match may not be exhaustive.It would fail on the following input: Russia// def from(m: Man) = m match {// 如果确定不会有 Russia 类型的对象传入,可以使用下面的方法去掉警告提示def from(m: Man) = (m : @unchecked) match {case American ⇒ println("American")case Chinese ⇒ println("Chinese")}
这篇关于Scala 入门-模式匹配的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!