如何将转换链的结果传递给函数?

时间:2013-12-01 06:00:44

标签: scala higher-order-functions

我想编写一系列转换,最后有一个块,我可以使用生成的集合执行某些操作,而不使用变量。 在集合上是否有一个更高阶的函数,它只是提供它被调用到所提供函数的集合?

Query( ... )
  .map { ... }
  .filter { ... }
  .combinations(2)
  .pipeTo { col =>
     ...
     consolidate(col)
  }

当然,对于单个函数调用,可以这样做:

consolidate(
  Query()
    .map { ... }
    .filter { ... }
    .combinations(2)
)

但前者对我来说更自然,并允许例如为了容易注入一些条件。

我一直在使用的解决方法是在最后放置一个匹配条款:

Query()
  .map { ... }
  .filter { ... }
  .combinations(2)
  match { case lst =>
    ...
    consolidate(lst)
  }

但由于这种模式经常发生,我想知道写这个的惯用方法是什么。

1 个答案:

答案 0 :(得分:7)

也许最习惯的方式是使用所谓的Pimp My Library Pattern,它允许通过隐式类转换向任何类添加扩展方法。

例如,要向consolidate添加List方法,您可以写:

object ListExtensions {
  implicit class ConsolidatableList[T](val lst: List[T]) extends AnyVal {
    def consolidate = ??? // Do whatever you want with the List lst
  }
}

import ListExtensions._

List(1,2,3)
  .map(x => x * x)
  .consolidate

如果你真的希望能够在链中的任意对象上调用任意函数,你甚至可以在F#中定义一个“管道”运算符:

object Extensions {
  implicit class PipelineExtension[T](val obj: T) extends AnyVal {
    def |>[S](f: T => S): S = f(obj)
  }
}

import Extensions._

List(1,2,3)
  .map(x => x * x) 
  .|> (consolidate)

Query( ... )
  .map { ... }
  .filter { ... }
  .combinations(2)
  .|> { col =>
     ...
     consolidate(col)
  }

|>运算符的行为类似于您定义的pipeTo方法。

基本上,这可以通过使用您定义的各种扩展方法创建从类型到类型的隐式转换。 AnyVal使扩展类成为一个值类,因此它的使用几乎没有运行时成本。