【问题标题】:How to convert Option[Try[_]] to Try[Option[_]]?如何将 Option[Try[_]] 转换为 Try[Option[_]]?
【发布时间】:2016-08-10 12:52:00
【问题描述】:

我经常使用下面的函数将Option[Try[_]]转换为Try[Option[_]],但感觉不对。这样的功能可以用更惯用的方式表达吗?

def swap[T](optTry: Option[Try[T]]): Try[Option[T]] = {
  optTry match {
    case Some(Success(t)) => Success(Some(t))
    case Some(Failure(e)) => Failure(e)
    case None => Success(None)
  }
}

假设我有两个值:

val v1: Int = ???
val v2: Option[Int] = ???

我想对这些值进行操作op(可能会失败)并将其传递给下面的函数f

def op(x: Int): Try[String]
def f(x: String, y: Option[String]): Unit

我通常用于理解可读性:

for {
  opedV1 <- op(v1)
  opedV2 <- swap(v2.map(op))
} f(opedV1, opedV2)

PS。我想避免一些沉重的东西,比如 scalaz。

【问题讨论】:

  • swap 的定义看起来很合理。我不知道你还能从中得到什么。
  • 一个想法:这个操作通常(习惯上?)称为sequence而不是swap

标签: scala optional traversable


【解决方案1】:

听起来像Try { option.map(_.get) } 会做你想做的事。

【讨论】:

  • 在我看来,像这样抛出和捕获异常有足够的开销(例如在运行时,但对读者来说更重要的是),因此 OPs 实现是更可取的,即使它不那么简洁。
  • 抛出异常的开销是多少(除了实例化它并填充堆栈,现在已经完成了)?我不知道它比调用函数要大得多。无论如何,我认为,如果有人关心抛出异常的开销,他不应该一开始就使用Try。或者 scala (在 scala 中有一些东西会造成更多的开销,并且比异常更难避免)。只需坚持使用“C”和 goto,以确保最大限度地减少开销 :)
  • 这就是为什么我强调人类读者的开销。我经常 grep for .get 调用 TryOption 来快速衡量一个对我来说是新的项目的健康状况,我不会例外,因为作者很聪明以拯救一对夫妇行并避免模式匹配。 :)
  • 好吧,那太糟糕了。我总是为聪明的人破例。我发现他们很难得到,值得不时地与愚蠢的人区别对待;)
  • @Dima 如果来自 Effective Java 的 Josh Bloch 的微基准测试是可以通过的,我希望抛出异常只是为了立即捕获比返回它的性能要低得多作为一个值。不管性能如何,在像 Scala 这样面向表达式的语言中,操作值而不是抛出异常被认为更惯用。我和特拉维斯一起做这个。
【解决方案2】:

此变体避免重新抛出:

import scala.util.{Failure, Success, Try}

def swap[T](optTry: Option[Try[T]]): Try[Option[T]] =
  optTry.map(_.map(Some.apply)).getOrElse(Success(None))

swap(Some(Success(1)))
// res0: scala.util.Try[Option[Int]] = Success(Some(1))

swap(Some(Failure(new IllegalStateException("test"))))
// res1: scala.util.Try[Option[Nothing]] = Failure(java.lang.IllegalStateException: test)

swap(None)
// res2: scala.util.Try[Option[Nothing]] = Success(None)

【讨论】:

    【解决方案3】:

    cats 库允许您非常轻松地将Option排序Try

    scala> import cats.implicits._
    import cats.implicits._
    
    scala> import scala.util.{Failure, Success, Try}
    import scala.util.{Failure, Success, Try}
    
    scala> Option(Success(1)).sequence[Try, Int]
    res0: scala.util.Try[Option[Int]] = Success(Some(1))
    
    scala> Option(Failure[Int](new IllegalArgumentException("nonpositive integer"))).sequence[Try, Int]
    res1: scala.util.Try[Option[Int]] = Failure(java.lang.IllegalArgumentException: nonpositive integer)
    
    scala> None.sequence[Try, Int]
    res2: scala.util.Try[Option[Int]] = Success(None)
    

    【讨论】:

      猜你喜欢
      • 2018-09-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-27
      • 2019-05-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多