模式匹配有一个方面我不理解。
在模式匹配的文档中,他们显示了一个示例,例如:
https://docs.scala-lang.org/tour/pattern-matching.html
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
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")
可以在java中重新编码,例如:
Notification notification = /* Init a notification instance */
if(notification instanceof Email) {
Email currentEmail = (Email) notification;
currentEmail.doSomething();
} else if (notification instanceof SMS) {
SMS currentSMS = (SMS) notification;
currentSMS.doSomething();
} else if {
/* ... */
}
模式匹配似乎被非常积极地看待,但恰恰相反,java等价物被视为"匹配";代码气味";或者坏模式。
据我所知,他们正在做同样的事情,也许在技术上也是如此,这只是为了scala模式匹配而隐藏的。
然而,这样的双重标准不会被忽视,所以我想我的理解有问题。
在底层,Scala模式匹配通常可以归结为与if (notification instanceof Email) { ... } else if (notification instanceof SMS)
Java代码完全相似的代码。
您给出的不是sealed
的abstract class Notification
的特定示例中,Scala代码并不比if
/instanceof
树更好(除了可能更清楚地表达总体意图之外(。
这是因为模式匹配的主要好处是可以进行穷尽性检查。使用if
/instanceof
方法和您提供的模式匹配示例,您不会被提醒您没有处理每一个案例(例如,您忽略了VoiceRecording
案例(。
通过使Notification
成为sealed
(例如sealed abstract class Notification
(,Scala编译器将确保其他文件(从技术上讲,编译单元,用于所有意图和目的的文件(中的Scala代码都不能扩展Notification
;由于它现在知道所有可能的Notification
,因此如果您错过了一个案例,它可能会引发编译器错误。在if
/instanceof
的情况下,没有可靠的方法可以做到这一点,因为这是一个较低级别的抽象。
;气味;具有历史意义。面向对象的设计建议您应该能够让类型层次结构将方法调用分派到适当的子类型,而不是在调用站点检查实际实例。曾经有一些与过度使用继承有关的糟糕设计,导致了instanceof
的使用。instanceof
的使用并不是坏事,但它暗示了类型层次结构可能不好。
另一方面,Java17现在也有Scala的模式匹配(作为预览功能,很快就会完成(,所以你不能真的说在Java中使用instanceof
是件坏事。