class 匹配和访问 Option[List] 的最后一个的更简洁的方法

More concise way to class match and access last of Option[List]

我有一个函数,它接受一个对象作为参数,如果它是正确的类型,我需要访问 Option[List[Int]] 中的最后一个元素。我有一个可行的解决方案,但它看起来很笨拙。如果 obj.listOfThings 中没有任何项目,我需要 i 的值为 0。有没有更好的方法来实现这一点?

val i = foo match {
  case obj: Bar =>
    obj.listOfInts match {
      case Some(ints) =>
        ints.last
      case _ =>
        0
    }
  case _ =>
    0
}

从技术上讲,它可以 return 和 Option[Int]。我对 Scala 还是很陌生,想学习更好的方法来解决这类问题。

根据评论中的建议,我认为最好的方法是:

val i = foo match {
  case obj: Bar => obj.listOfInts.map(_.last).getOrElse(0)
  case _        => 0
}

在您的情况下,Ende Neu 最初的建议似乎是正确的方法:

val i = foo match {
  case obj: Bar =>
     obj.listOfInts.map(_.last /* This throws an exception when the list is empty*/).getOrElse(0)
  case _ =>
    0
}

但是如果你仔细研究它,你会发现你的代码中有一个错误,在 obj.listOfInts is Some(Nil) 的情况下,因为在那种情况下你会得到一个 NoSuchElementException 试图最后调用一个空列表。

foo = Bar(Some(Nil)) 试试这个代码,然后自己看看。

当您使用 Option[List] 时,请仔细考虑这是否是您想要的。 通常经过一番思考后,您会放弃该选项并继续使用列表,因为该选项没有任何用处。 我与许多滥用 Option[List] 的开发人员一起工作,因为他们不了解 Nil 和 None 之间的相似之处,通常 'None' 案例最终扮演与 Some(Nil)

相同的角色

所以你最终不得不这样做:

optionalList match {
    case None => // do something
    case Some(list) =>
        list match {
            case Nil => // do the same thing
            case head::tail => // do other stuff
        }
}

如您所见,None 情况和 Some(Nil) 情况基本相同。

要修复您的错误,您应该这样做:

  case class Bar(listOfInts: Option[List[Int]])

  val i = foo match {
    case Bar(Some(list)) if list != Nil => list.last
    case _ => 0
  }

你可能想在这里使用 flatMaplastOption:

obj.listOfInts.flatMap(_.lastOption)

如果 listOfIntsNone,或者是 Some(Nil),这将 return None。否则它将 return 最后一个元素。如果您想 return 0 而不是 None,只需使用 getOrElse:

obj.listOfInts.flatMap(_.lastOption).getOrElse(0)

如果你想使用火柴,你可以这样做:

obj.listOfInts match {
    case Some(list@(hd::tl)) => list.last
    case _ => 0
}

这里,hd::tl保证list不为空。另一种选择是使用条件匹配:

obj.listOfInts match {
    case Some(list) if list.nonEmpty => list.last
    case _ => 0
}

或者先匹配 NoneSome(Nil) 的情况:

obj.listOfInts match {
    case None | Some(Nil) => 0
    case Some(list) => list.last
}

包括instanceof在内的更简洁的方式:

scala> case class B(is: Option[List[Int]])
defined class B

scala> def f(x: Any) = Option(x) collect { case b: B => b.is flatMap (_.lastOption) } flatten
f: (x: Any)Option[Int]

scala> f(B(Option(5 to 7 toList)))
res0: Option[Int] = Some(7)

scala> import PartialFunction.{ condOpt => when }
import PartialFunction.{condOpt=>when}

scala> def g(x: Any) = when(x) { case b: B => b.is flatMap (_.lastOption) } flatten
g: (x: Any)Option[Int]

scala> g(B(Option(5 to 7 toList)))
res1: Option[Int] = Some(7)

可能值得一问为什么你丢失了静态类型信息,你需要模式匹配。