【问题标题】:Short circuit Map Operation If Try Fails尝试失败时的短路映射操作
【发布时间】:2020-05-27 09:21:45
【问题描述】:

我有这样的功能:

def foo(item: Item) : Option[Int] = Try{
  // Some code that can blow up
}.toOption

我有一个项目列表,我想通过它们进行映射,并应用上述功能。但是如果上面的函数爆炸并返回一个 None 那么映射的结果应该是一个错误:

items.map{
  item => foo(item)
}

在这里做地图不合适吗?好像没有

【问题讨论】:

    标签: scala short-circuiting


    【解决方案1】:

    这称为traverse。如果你可以使用cats,那么简单如下:

    import cats.implicits._
    
    val result = items.traverse(foo) // Option[List[Int]]
    

    如果没有,你可以很容易地实现它:

    def traverse[A, B](data: List[A])(f: A => Option[B]): Option[List[B]] = {
      @annotation.tailrec
      def loop(remaining: List[A], acc: List[B]): Option[List[B]] =
        remaining match {
          case a :: as => f(a) match {
            case Some(b) => loop(remaining = as, b :: acc)
            case None => None
          }
    
          case Nil => Some(acc.reverse)
        }
    
      loop(remaining = data, acc = List.empty)
    }
    

    你可以像这样使用:

    val result = traverse(items)(foo) // Option[List[Int]]
    

    (不过,我建议你改用 cats,因为它更通用)

    【讨论】:

    • 所以在第一次失败时,这将返回 None 整体?
    • @Mojo 是的,它将停止处理它找到的第一个None。您可以证明手工实现可以做到这一点,这就是 cats 版本的作用。
    • @Mojo 对于我最近遇到的几乎所有“小问题”cats 中有一个函数以非常通用的方式完成.当该功能不存在时,使用提供的功能很容易创建。这就是函数式编程的力量,我真的建议你阅读一下。
    【解决方案2】:

    对于开箱即用的短路,请考虑使用 Try 包装列表映射

    def fooUnsafe(item: Item): Int = // might throw
    Try(items.map(fooUnsafe))
    

    如果您希望保留def foo(item: Item) : Option[Int] 签名,则以下内容也会短路

    Try(list.map(v => foo(v).get))
    

    【讨论】:

    • 问题是微不足道的,这是微不足道的解决方案。
    猜你喜欢
    • 2015-05-03
    • 2017-01-10
    • 2023-03-29
    • 1970-01-01
    • 2012-11-07
    • 1970-01-01
    • 2022-06-14
    • 1970-01-01
    • 2011-11-17
    相关资源
    最近更新 更多