为什么模式匹配在 scala 中没问题,但在 Java 中使用 instanceof 却是糟糕代码的标志

Rob*_*lds 5 java scala

我不明白模式匹配的一个方面。

在模式匹配的文档中,他们显示了一个示例,例如:

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")
Run Code Online (Sandbox Code Playgroud)

可以用 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 {
    /* ... */
}
Run Code Online (Sandbox Code Playgroud)

模式匹配似乎被非常积极地看待,但相反,Java 等价物被视为“代码味道”或糟糕的模式。

据我了解,他们正在做同样的事情,也许技术上也是如此,它只是为了 scala 模式匹配而隐藏。

但这样的双重标准是不会消失的,所以我想我的理解有问题。

Lev*_*sey 11

在底层,Scala 模式匹配通常可以归结为与 Java 代码完全相同的代码if (notification instanceof Email) { ... } else if (notification instanceof SMS)

您给出的特定示例中, Scala 代码abstract class Notification并不比/树sealed更好(除了可能更清楚地表达整体意图)。ifinstanceof

这是因为模式匹配的主要好处是可以进行穷举检查。使用if/instanceof方法和您提供的模式匹配示例,您不会被提醒您尚未处理所有情况(例如,您没有处理该VoiceRecording情况)。

通过制作Notification sealed(例如sealed abstract class Notification),Scala 编译器将确保其他文件(从技术上讲,编译单元,用于所有意图和目的文件)中的 Scala 代码不能扩展Notification;因为它现在知道所有可能的Notifications,所以如果您错过了一个案例,它可能会引发编译器错误。if在/情况下没有可靠的方法来执行此操作,instanceof因为这是较低的抽象级别。