对Scala的选项类型执行“tee”操作?

g6baxovj  于 12个月前  发布在  Scala
关注(0)|答案(4)|浏览(125)

在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


有什么建议吗?

ru9i0ody

ru9i0ody1#

为了避免隐式转换,而不是使用方法链,你可以使用函数组合与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

t9eec4r0

t9eec4r02#

在标准库中没有现有的方法来完成这一任务,因为函数式编程中的副作用被最小化和隔离。根据您的实际目标,有几种不同的方法可以按习惯完成任务。
在执行大量println命令的情况下,而不是将它们分散在整个算法中,您通常会将它们收集在一个集合中,然后在最后执行一个foreach println。这将副作用最小化到最小可能的影响。这与任何其他副作用有关。尝试找到一种方法将其压缩到最小可能的空间中。
如果你想链接一系列的“动作”,你应该研究一下futures。Futures基本上把动作当作一个值,并提供了很多有用的函数来处理它们。

pdtvr36n

pdtvr36n3#

简单地使用map,让你的副作用函数符合action: A => A而不是action: A => Unit

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

字符串

bmvo0sr5

bmvo0sr54#

从Scala 2.13开始,我们可以使用scala.util.ChainingOps#tap。
范例:

import scala.util.chaining._

val result = Option(1)
  .tap(x => println(s"Input: $x"))
  .map(_ + 1)
  .tap(x => println(s"Output: $x"))

字符串
测试结果:

Input: Some(1)
Output: Some(2)
val result: Option[Int] = Some(2)

相关问题