我最近写了以下Scala:
val f: File = ... // pretend this file came from somewhere
val foo = toFoo(io.Source.fromFile(f).mkString)
Run Code Online (Sandbox Code Playgroud)
我真的不喜欢这种流动的方式.要了解发生了什么,你必须从f中间开始,向左fromFile阅读,向右mkString阅读,再向左阅读toFoo.啊.
特别是在习惯了序列的功能转换之后,这很难理解.我的下一次尝试看起来像这样:
val foo = Some(f)
.map(io.Source.fromFile)
.map(_.mkString)
.map(toFoo)
.get
Run Code Online (Sandbox Code Playgroud)
我喜欢这个更好的流程.你可以看到会发生什么这是一个很好的使用Option课程?还是我在滥用它?有没有更好的模式可以用来实现相同的流程?
Rex*_*err 27
这完全没问题.然而,有一种方法|>在Scalaz,做一个更好的,你可以自己创建它,如果你不希望所有Scalaz的:
class Piper[A](a: A) { def |>[B](f: A => B) = f(a) }
implicit def pipe_everything[A](a: A) = new Piper(a)
f |> io.Source.fromFile |> {_.mkString} |> toFoo
Run Code Online (Sandbox Code Playgroud)
就个人而言,我倾向于编写大量需要括号的代码,而且在大多数情况下我喜欢比运算符更好的方法,所以在我的代码中我通常称之为|>"use",但这是相同的交易:
f.use(io.Source.fromFile).use(_.mkString).use(toFoo)
Run Code Online (Sandbox Code Playgroud)
在Scala 2.11或更高版本中,您可以使用(略微)较少的语法获得相同的行为和改进的性能:
implicit class Piper[A](private val a: A) extends AnyVal {
def |>[B](f: A => B) = f(a)
}
Run Code Online (Sandbox Code Playgroud)
我对这里给出的其他答案没有任何问题,但您是否考虑将toFoo的名称更改为"流动"更好的内容?我的意思是,toFoo真的闻起来应该在表达式的右边,但是如果你把它重命名为其他东西,它也可能适合左边.
// toFoo, as defined by you
val foo = toFoo(io.Source.fromFile(f).mkString)
// Same function, different name
val foo = createFooFrom(io.Source.fromFile(f).mkString)
Run Code Online (Sandbox Code Playgroud)