Conditional invocation of a method in Scala
I've found this pattern quite a few times in my code:
if (doIt)
object.callAMethod
else
object
I'm wondering if there could be a syntactically more pleasing way to write the code above, especially to avoid the repetition of the object
variable. Something like:
// using the Scalaz "pipe" operator
// and "pimping" f: T => T with a `when` method
object |> (_.callAMethod).when(doIt)
Unfortunately the line above fails because the type inference requires a parameter type for (_.callAMethod)
.
My best approach for now is this:
implicit def doItOptionally[T](t: =>T) = new DoItOptionally(t)
class DoItOp开发者_JAVA技巧tionally[T](t: =>T) {
def ?>(f: T => T)(implicit doIt: Boolean = true) =
if (doIt) f(t) else t
}
implicit val doIt = true
object ?> (_.callAMethod)
Not great because I have to declare an implicit val
but this pays off if there are several chained calls:
object ?> (_.callAMethod) ?> (_.callAnotherMethod)
Does anyone have a better idea? Am I missing some Scalaz magic here?
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)
Example:
scala> "fish".when(_.length<5)(_.toUpperCase)
res2: java.lang.String = FISH
I can't comment on your answer @Rex Kerr but a more concise way to do that would be:
implicit class When[A](a: A) {
def when(f: A => Boolean)(g: A => A) = if (f(a)) g(a) else a
}
Just putting the implicit
before the class allows you to omit the implicit function entirely.
If you represent your callAMethod
as an endomorphism then you can use the monoid functionality. Something like:
object |> valueOrZero(doIt, Endo(_.callAMethod))
(might need a type parameter on the Endo
)
精彩评论