检查 Scala 匹配表达式中的两个特定异常

Check two specific exceptions in a match expression in Scala

所以我在 Scala 中有一个 Try 块

  def fromString(s: String): Option[Pitch] = scala.util.Try {
    val (pitchClassName, octaveName) = s.partition(c => !c.isDigit)
    val octave = if octaveName.nonEmpty then octaveName.toInt else 5
    Pitch(pitchClassIndex(pitchClassName) + octave  * 12)
  } match {
    case scala.util.Success(value) => Some(value)
    case scala.util.Failure(e) => 
    case scala.util.Failure(e) => throw e
  }

现在,我知道这里有很多代码需要解释。为了这个问题的目的,虽然需要知道的是:

当使用给定音符(如“D#4”)创建 Pitch 实例时,可能有两个不同的异常需要我专门处理。第一个是如果 Map pitchClassIndex 找不到给定的键 pitchClassName,第二个是如果 Pitch 参数超出给定范围。

pitchClassIndex:

val pitchClassIndex: Map[String, Int] = pitchClassNames.zipWithIndex.toMap

音高类名称:

val pitchClassNames: Vector[String] = Vector("C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B")

所以现在我们输入 s: String 并检查它是否有数字,如果有则将其拆分为元组 val (pitchClassName, octaveName) 如果 s = "D#4" 现在元组为 ("D#", "4") val octave = 4 所以现在在创建我们的 Pitch 实例时,我们将从键 pitchClassName: String = "D#" 中获取 pitchClassIndex: Map[String, Int] 中的值(请注意,如果 pitchClassName 不对应于 pitchClassNames 中的值,我们将获得一个例外)然后我们将先乘以 12 添加 octave: Int = 4Pitch(51) 现在 Pitch 的前两行看起来像这样:

case class Pitch(nbr: Int):
  assert((0 to 127) contains nbr, s"Error: nbr $nbr outside (0 to 127)")

因此,如果传入 Pitch 的参数超出范围 (0 to 127),则抛出 AssertionError 并显示错误消息。

所以现在我们有 两种 可以抛出异常的情况,第一种是开头的断言。第二个是如果 pitchClassIndex(pitchClassName) 使用 pitchClassNames: Vector[String] 中不包含的密钥,例如“K#”。然后它会抛出一个 NoSuchElementException 消息:“找不到密钥:K#”

现在如您所见,我在测试 Try 语句的匹配表达式中有一个空的失败案例,在这种情况下,我想检查异常 e 是 AssertionError 还是 NoSuchElementException,以及它是否是其中之一我想打印一些特殊的文字。最后一种情况是针对其他例外情况。但是我不太确定如何测试这个?有什么我可以在失败中写的东西,比如 (e: ???) 有什么想法吗?

您可以为两个例外添加两个 case 子句

case Failure(e: AssertionError) => 
  // do something
case Failure(e: NoSuchElementException) => 
  // do something else
case Failure(e) =>
  // goes here for other exceptions

如果您想将它们合并为一个案例,您将无法再在变量 e 中捕获详细信息,因此这可能不是一个选项:

case Failure(_: AssertionError) 
      | Failure(_: NoSuchElementException)     => 
   // cannot use `e` anymore 

我想你可以诉诸 .isInstanceOf

case Failure(e) 
  if e.isInstanceOf[AssertionError] ||
     e.isInstanceOf[NoSuchElementException] =>
   // now `e` is Throwable in here