Clojure 具有“线程宏”->
和->>
. 我很确定可以在 Scala 代码中使用类似的结构来替换以下代码:
var myObj = MyObject(x, y, z)
myObj = transform(myObj, abc)
myObj = transformMore(myObj, def)
myObj = transformYetMore(myObj, bar)
我很想看到一个可行的例子,看看它是否看起来不错。我很确定您不需要在 Scala 案例中使用宏。
好问题!我可以想到几个这样的例子可以派上用场。举个例子,我正在处理一个数据集,我想在它上面应用几个函数,同时将结果向前推进,如下所示:
val result: ResultSet = Functions.thread(inputSet)
.andThen(execute(_, executionContext))
.andThen(_.filter(_.nonEmpty))
.andThen(verifyData(_, verificationHelper))
.andThen(_.cache)
.andThen(saveSnapshot)
要在没有线程的情况下编写相同的代码,您将需要嵌套调用或保存中间函数调用的结果。我更喜欢使用上述方法,因为它用更少的行数做同样的事情,从而提高了我的代码的可维护性和可读性。
这是Functions
实现此目的的实用程序:
object Functions {
def thread[T](item: T) = new ThreadFunctor(item)
}
class ThreadFunctor[T](val item: T) {
def andThen(f: T => T): ThreadFunctor[T] = new ThreadFunctor(f(item))
}
object ThreadFunctor {
implicit def threadToItem[T](thread: ThreadFunctor[T]): T = thread.item
}
clojure 中的线程宏用于解决过度嵌套表达式的问题,因此在 scala 中使用某种线程实用程序非常罕见(尽管原则上是可能的,正如 Stefan 所提到的),因为普通的集合函数很好
def square(x: Int) = x * x
def plusOne(x: Int) = x + 1
List(1,2,3,4).map(square).map(plusOne)
甚至是冗长的:
someCollection.map(...)
.flatMap(...)
.filter(...)
.map(...)
...
另一种选择是用于理解(对期权和期货更有用)。如果你对此不满意,你不需要使用宏,有很多关于这种结构的博客文章,例如这个