13

我在我的代码中多次发现这种模式:

  if (doIt)
    object.callAMethod
  else
    object

我想知道是否有一种语法上更令人愉悦的方式来编写上面的代码,尤其是避免object变量的重复。就像是:

   // using the Scalaz "pipe" operator
   // and "pimping" f: T => T with a `when` method
   object |> (_.callAMethod).when(doIt)

不幸的是,上面的行失败了,因为类型推断需要一个参数类型(_.callAMethod)

我现在最好的方法是:

    implicit def doItOptionally[T](t: =>T) = new DoItOptionally(t)
    class DoItOptionally[T](t: =>T) {
      def ?>(f: T => T)(implicit doIt: Boolean = true) = 
        if (doIt) f(t) else t
    } 

    implicit val doIt = true
    object ?> (_.callAMethod)

不是很好,因为我必须声明一个,implicit val但如果有几个链式调用,这会得到回报:

     object ?> (_.callAMethod) ?> (_.callAnotherMethod)

有没有人有更好的主意?我在这里错过了一些 Scalaz 魔法吗?

4

3 回答 3

18
class When[A](a: A) {
  def when(f: A => Boolean)(g: A => A) = if (f(a)) g(a) else a
}
implicit def whenever[A](a: A) = new When(a)

例子:

scala> "fish".when(_.length<5)(_.toUpperCase)
res2: java.lang.String = FISH
于 2011-09-05T23:47:02.453 回答
4

我无法评论您的回答@Rex Kerr,但更简洁的方法是:

implicit class When[A](a: A) {
  def when(f: A => Boolean)(g: A => A) = if (f(a)) g(a) else a
}

只需将 放在implicit类之前,您就可以完全省略隐式函数。

于 2016-03-02T21:07:05.157 回答
0

如果您将您的表示callAMethod为内同态,那么您可以使用幺半群功能。就像是:

object |> valueOrZero(doIt, Endo(_.callAMethod))

(可能需要一个类型参数Endo

于 2016-03-02T23:09:44.130 回答