invocazione condizionale di un metodo in Scala
Domanda
Ho trovato questo modello di un bel paio di volte nel mio codice:
if (doIt)
object.callAMethod
else
object
Mi chiedo se ci potrebbe essere un modo sintatticamente più piacevole di scrivere il codice di cui sopra, in particolare al fine di evitare la ripetizione della variabile object
. Qualcosa di simile:
// using the Scalaz "pipe" operator
// and "pimping" f: T => T with a `when` method
object |> (_.callAMethod).when(doIt)
Purtroppo la linea di cui sopra non riesce perché l'inferenza di tipo richiede un tipo di parametro per (_.callAMethod)
.
Il mio approccio migliore per ora è questo:
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)
Non è fantastico, perché devo dichiarare un implicit val
ma questo ripaga se ci sono diverse chiamate concatenati:
object ?> (_.callAMethod) ?> (_.callAnotherMethod)
Qualcuno ha un'idea migliore? Mi sto perdendo un po 'di magia Scalaz qui?
Soluzione
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)
Esempio:
scala> "fish".when(_.length<5)(_.toUpperCase)
res2: java.lang.String = FISH
Altri suggerimenti
Non posso commentare sul tuo risposta @Rex Kerr, ma una concisa altro modo per farlo sarebbe:
implicit class When[A](a: A) {
def when(f: A => Boolean)(g: A => A) = if (f(a)) g(a) else a
}
Basta mettere il implicit
prima della classe consente di omettere la funzione implicita del tutto.
Se rappresentate tuo callAMethod
come un endomorfismo quindi è possibile utilizzare la funzionalità monoide. Qualcosa di simile:
object |> valueOrZero(doIt, Endo(_.callAMethod))
(potrebbe essere necessario un parametro di tipo sul Endo
)