2013-08-21 8 views
7

Dlaczego po wpisaniu tego wszystko działa poprawnie?Scala.A i getOrElse method

Right(2).left getOrElse Right(4).left getOrElse Left("Error") 

ale kiedy piszę tę kompilację nie?

Right[String, Int](2).left getOrElse Right[String, Int](4).left getOrElse Left[String, Int]("Error") 

błąd kompilacji:

value getOrElse is not a member of java.io.Serializable
println(RightString, Int.left getOrElse RightString, Int.left getOrElse LeftString, Int)

Więc nie mogę łańcuch getOrElse wywołanie metody

+0

Wygląda to na szczególnie niejasny sposób na uzyskanie dość prostego zachowania polegającego na upadku. Dlaczego po prostu nie napisać tego inaczej, niż próbować dopasować pożądane zachowanie do tych metod? –

Odpowiedz

8

Podpis getOrElse dla LeftProjection[A, B] jest:

def getOrElse[AA >: A](or: ⇒ AA): AA 

czyli oczekuje argument musi być pewnego rodzaju AA, który jest nadtypem A.

W pierwszym przykładzie pominięto adnotacje typu, pozwalając kompilatorowi wywnioskować Nothing dla A. Następnie podałeś argument typu LeftProjection[Nothing, Int].

Ponieważ Nothing jest podtypem wszystkich typów, LeftProjection[Nothing, Int] jest trywialnie supertypem! Ten szczególny przypadek w systemie typu oznacza, że ​​został on sprawdzony prawie przypadkowo.

Jednak najbardziej charakterystycznym typowym nadtypem String i LeftProjection[String, Int] jest Serializable.


Tak więc, jeśli chcesz łańcucha Either s, trzeba metodę, która może podjąć inną Either[A, B], a nie tylko A lub B.

Metoda wydaje się chcieć będzie wyglądać następująco:

def leftOrElse[A, B](e1: Either[A, B], e2: => Either[A, B]): Either[A,B] = 
    e1 match { 
    case Left(a) => Left(a) 
    case Right(b) => e2 
    } 

(Można podobnie napisać rightOrElse, który jest bardziej powszechne przypadek użycia).

Staje składniowo nieco bardziej użyteczny, jeśli czynisz z niej metodę rozszerzenia, używając implicite.

implicit class EitherOps[A, B](e1: Either[A, B]) { 
    def leftOrElse(e2: => Either[A, B]): Either[A,B] = // as above 
} 

Ponieważ oczekuje Either[A, B] dla obu argumentów, zamiast A lub B (lub pewne jego supertypem), można łańcuch swoich Either jesteś ty.

scala> Right[String, Int](2) leftOrElse Right[String, Int](4) leftOrElse Left[String, Int]("Error") 
res1: Either[String,Int] = Left(Error)