2011-09-05 19 views
11

Znalazłem ten wzór dość kilka razy w moim kodu:Warunkowe wywołanie metody w Scala

if (doIt) 
    object.callAMethod 
    else 
    object 

Zastanawiam się, czy nie może być składniowo bardziej przyjemny sposób napisać powyższy kod, szczególnie, aby uniknąć powtórzenia zmiennej object. Coś jak:

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

Niestety linia powyżej nie powiedzie, ponieważ typ wnioskowanie wymaga typ parametru dla (_.callAMethod).

Moim najlepszym podejściem do teraz jest to:

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) 

Nie super, bo muszę zadeklarować implicit val ale to się opłaca, jeżeli istnieje kilka łańcuchu połączenia:

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

Czy ktoś ma lepszy pomysł? Czy brakuje mi tutaj magii Scalaz?

Odpowiedz

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

Przykład:

scala> "fish".when(_.length<5)(_.toUpperCase) 
res2: java.lang.String = FISH 
+0

nie myślałem o odwrócenie stanu i funkcji, dzięki! – Eric

+0

Zauważam też, że rzeczownik idzie tu lepiej niż operator, ponieważ '.' musi być użyty po' "fish" '. – Eric

2

nie mogę wypowiedzieć się na temat swojej odpowiedzi @Rex Kerr bardziej zwięzły sposób to zrobić byłoby:

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

Tuż przed uruchomieniem implicit klasa pozwala całkowicie pominąć funkcję domniemaną.

0

Jeśli reprezentujesz swoją callAMethod jako endomorfizm, możesz użyć funkcji monoid. Coś jak:

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

(może potrzebować parametr typu na Endo)