Option包装值是一个好的模式吗?

时间:2011-02-03 17:11:39

标签: scala

我最近写了以下Scala:

val f: File = ... // pretend this file came from somewhere
val foo = toFoo(io.Source.fromFile(f).mkString)

我真的不喜欢这种流动的方式。要了解正在发生的事情,您必须从中间的f开始,向左阅读fromFile,向右阅读mkString,再向左阅读toFoo。啊。

特别是在习惯了序列的功能转换之后,这很难理解。我的下一次尝试看起来像这样:

val foo = Some(f)
  .map(io.Source.fromFile)
  .map(_.mkString)
  .map(toFoo)
  .get

我更喜欢这种流程。你可以看到会发生什么这是Option类的好用吗?还是我在滥用它?有没有更好的模式可以用来实现相同的流程?

3 个答案:

答案 0 :(得分:26)

这完全没问题。但是,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

就个人而言,我倾向于编写大量需要括号的代码,而且在大多数情况下我比运算符更喜欢方法,所以在我的代码中我通常称|>“使用”,但这是相同的交易:< / p>

f.use(io.Source.fromFile).use(_.mkString).use(toFoo)

在Scala 2.11或更高版本中,您可以使用(略微)较少的语法获得相同的行为并提高性能:

implicit class Piper[A](private val a: A) extends AnyVal {
  def |>[B](f: A => B) = f(a)
}

答案 1 :(得分:5)

我对这里给出的其他答案没有任何问题,但您是否考虑将toFoo的名称更改为“流动”更好的内容?我的意思是,toFoo真的闻起来应该在表达式的 right 上,但是如果你把它重命名为其他东西,它也可能适合 left

// 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)

答案 2 :(得分:4)

您通过pimp my library模式将toFoo添加到String。然后它变成:

val foo = Source fromFile f mkString () toFoo