将Seq[T]转换为Option[Seq[T]]



Scala Seq包含对空序列非法或未定义的方法,例如max

为了避免这种情况,我通常通过将序列包装在一个选项中并将空映射为None来解决这个问题。可以这样做:

def wrap[T](s: Seq[T]): Option[Seq[T]] =
    s.headOption map { _ => s }

也可以通过模式匹配或if-else来解决。

这些方法都不容易流畅地使用,坦率地说,看起来有点尴尬。

我希望能够做这样的事情:

someStore
   .giveMeASequence
   .wrapInOption map { nonEmpty:Seq[T] =>
      nonEmpty.max
    } map (_ + 42)

我很犹豫是否将操作包装在Try单子中,因为可以预测和避免异常。

我处理问题的方式不对吗?

如果没有,有什么库方法可以让我不那么尴尬吗?

如果你只是想做转换,为什么不使用If/else?

def wrap[A](s: Seq[A]) = if (s.isEmpty) None else Some(s)
或者,您可以定义自己的maxOpt方法:
implicit def seqWithMaxOpt[A:Ordering](s:Seq[A]) =
  new { def maxOpt = Try(s.max).toOption }

这样称呼

val s:Seq[Int] = Seq()
s.maxOpt

以同样的方式,您可以添加一个方法来在Option中包装一个序列:

   implicit def seqWithOptionWrapping[A](s:Seq[A]) =
  new { def wrapInOption = if (s.isEmpty) None else Some(s) }

正如我在评论中提到的,scalaz NonEmptyList类可能对您有帮助。通过导入scalaz pimping,您可以访问toNel方法,您可以在List上调用该方法。如果此列表确实为空,则不能继续在其上进行映射。如果它不是空的,就可以映射到它上面。考虑下面的例子:

import scalaz._
import Scalaz._
val nonEmpty = List(1,2,3)
val result = 
  nonEmpty.
    toNel.
    map(_.list.max).
    map(_ + 42)
println(result)

如果运行这段代码,它将打印Some(45)。如果该列表为空,则会产生None .

您可以通过隐式类使用安全方法扩展Seq:

 implicit class SafeSeq[T](s: Seq[T]) {
    def safeMax(implicit cmp: Ordering[T]): Option[T] =
      if (s.isEmpty) None
      else Some(s.max)
    //other safe operations you want
  }
  println(Seq.empty[Int].safeMax.map(_ + 42)) // None
  println(Seq(1).safeMax.map(_ + 42))         // Some(43)   

最新更新