编写以下内容的惯用方法是什么?
val starting_value = ...
val result1 = f1(startingValue)
val result2 = f2(result1)
...
val resultN = fN(resultN-1)
如果starting_value
是我想要应用这些功能的项目列表,我可以写
starting_list.map(f1).map(f2)...map(fN)
我可以通过做
这样的事来伪造这个Some(starting_value).map(f1)....map(fN).get
或
List(starting_value).map(f1)....map(fN).head
但这似乎不必要地混淆。
注意:This question似乎有关,但似乎是关于下游问题。
答案 0 :(得分:10)
(f1 andThen f2 andThen ... fN) {
startingValue
}
答案 1 :(得分:4)
使用正向管道运算符。例如(对于def f(s: String) = s.length
):
scala> "abc" |> f |> 0.until
res16: scala.collection.immutable.Range = Range(0, 1, 2)
您可以在Scalaz中找到它,但您也可以找到它的定义elsewhere。
答案 2 :(得分:2)
您可以定义一个也是value class的扩展类。值类是一种特殊的Scala构造,它在新的编译时类型中包含单个值,但是包含相同的运行时对象,从而避免任何新的内存分配。该课程看起来像:
implicit class Piper[A](val x: A) extends AnyVal {
def |>[B](f: A => B) = f(x)
}
现在你做的时候:
startingValue |> f1 |> f2 |> ... |> fN
Scala在编译时隐式包装Piper
对象中的起始值和每个中间值,并应用Piper
对象的|>
方法,将中间值向前传递。在运行时不会产生额外的内存或时间成本。
答案 3 :(得分:-1)
您还可以考虑将值包装到Try中,然后在其上应用map(fN)。然后您将证明,如果任何函数失败,您将不会得到意外的异常。然后,您可以匹配成功/失败并进行一些恢复或仅打印确切的故障。