Метод Scala.Either 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")

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

значение getOrElse не является членом java.io.Serializable
println(RightString, Int.left getOrElse RightString, Int.left getOrElse LeftString, Int)

Поэтому я не могу связать вызов метода getOrElse


person MyTitle    schedule 21.08.2013    source источник
comment
Это выглядит как особенно неясный способ получить довольно прямое аварийное поведение. Почему бы просто не написать это по-другому, вместо того, чтобы пытаться впихнуть желаемое поведение в эти методы?   -  person Mysterious Dan    schedule 22.08.2013


Ответы (1)


Подпись 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, что является более распространенным вариантом использования.)

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

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 (или какого-то их супертипа), вы можете связать свои Eithers.

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