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