Scala选项类型的'tee'操作?

时间:2017-02-09 14:05:45

标签: scala functional-programming

Scala的标准库中Option是否有某种'tee'操作?我能找到的最好的是foreach,但其返回类型为Unit,因此无法链接。

这就是我要寻找的:给定一个Option实例,如果该选项不为空(Some[A]),则执行一些对其值有副作用的操作,否则什么都不做;在任何情况下都会返回选项。

我有一个使用隐式类的自定义实现,但我想知道是否有一种更常见的方法可以在没有隐式转换的情况下执行此操作:

object OptionExtensions {
  implicit class TeeableOption[A](value: Option[A]) {
    def tee(action: A => Unit): Option[A] = {
      value foreach action
      value
    }
  }
}

示例代码:

import OptionExtensions._

val option: Option[Int] = Some(42)
option.tee(println).foreach(println) // will print 42 twice

val another: Option[Int] = None
another.tee(println).foreach(println) // does nothing

有什么建议吗?

3 个答案:

答案 0 :(得分:3)

为了避免隐式转换,您可以将函数组合与k-combinator一起使用,而不是使用方法链接。 k-combinator为您提供了一种惯用的方式来传达您将要执行副作用的事实。

这是一个简短的例子:

object KCombinator {
  def tap[A](a: A)(action: A => Any): A = {
    action(a)
    a
  }
}

import KCombinator._

val func = ((_: Option[Int]).getOrElse(0))
  .andThen(tap(_)(println))
  .andThen(_ + 3)
  .andThen(tap(_)(println))

如果我们使用Option(3)参数调用我们的func,结果将是一个值为6的Int 这就是控制台的样子:

  

3

     

6

答案 1 :(得分:1)

只需使用地图,并使副作用函数符合action: A => A而不是action: A => Unit

 def tprintln[A](a: A): A = {
    println(a)
    a
 }
 another.map(tprintln).foreach(println) 

答案 2 :(得分:0)

在标准库中没有现成的方法可以实现这一点,因为在函数式编程中副作用被最小化和隔离。根据您的实际目标,可以通过几种不同的方式来完成您的任务。

如果要执行大量println命令,而不是在整个算法中使用它们,则通常会将它们收集到一个集合中,然后在最后执行一个foreach println。这可以最大限度地减少副作用,从而尽可能减小影响。这与任何其他副作用有关。尝试找到一种方法将其挤入尽可能小的空间。

如果您要尝试连锁一系列“行动”,您应该查看futures。期货基本上将行动视为一种价值,并提供许多有用的功能来与它们合作。