2013-08-21 3 views
7

Почему, когда я печатаю это, все работает нормально?Scala.Ely метод getOrElse

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

но когда я печатаю эту сборку, не удается?

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

Ошибка компиляции:

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

Так что я не могу цепь getOrElse вызова метода

+0

Это похоже на особенно неясный способ получить довольно прямолинейное поведение. Почему бы просто не написать его по-другому, вместо того, чтобы пытаться обучить ваше желаемое поведение этим методам? –

ответ

8

Подпись getOrElse для LeftProjection[A, B] является:

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

т.е. он ожидает аргумент какого-то типа AA, который является супертипом A.

В первом примере вы оставили аннотации типа, позволяющие компилятору вывести Nothing для A. Затем вы предоставили аргумент типа LeftProjection[Nothing, Int].

Поскольку Nothing является подтипом всех типов, LeftProjection[Nothing, Int] тривиального супертип! Этот специальный случай в системе типов означает, что он проверял тип почти случайно.

Однако наиболее распространенным видом супертипа String и LeftProjection[String, Int] является Serializable.


Итак, если вы хотите приковать Either с, вам нужен метод, который может занять другой Either[A, B], а не просто A или B.

Метод Вы, кажется, хотели бы выглядеть следующим образом:

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 
    } 

(Вы можете так же написать rightOrElse, что является более распространенным Прецедент.)

Это становится синтаксически немного более удобным, если вы делаете это методом расширения, используя implicits.

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

Поскольку это ожидает Either[A, B] для обоих операндов, вместо A или B (или некоторые супертип его), вы можете цепи ваши Either с.

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