Chữ ký của getOrElse
cho một LeftProjection[A, B]
là:
def getOrElse[AA >: A](or: ⇒ AA): AA
tức là nó hy vọng đối số là một số loại AA
là siêu kiểu của A
.
Trong ví dụ đầu tiên, bạn đã loại bỏ chú thích loại, cho phép trình biên dịch suy ra Nothing
cho A
. Sau đó, bạn đã cung cấp một đối số thuộc loại LeftProjection[Nothing, Int]
.
Vì Nothing
là một loại phụ của tất cả các loại, LeftProjection[Nothing, Int]
là tầm thường một siêu kiểu! Trường hợp đặc biệt này trong hệ thống kiểu có nghĩa là nó được kiểm tra gần như vô tình.
Tuy nhiên, loại siêu phổ biến cụ thể nhất của String
và LeftProjection[String, Int]
là Serializable
.
Vì vậy, nếu bạn muốn chuỗi Either
s, bạn cần có một phương pháp có thể mất một Either[A, B]
, không chỉ là một A
hoặc B
.
Phương pháp bạn dường như muốn sẽ trông như thế này:
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
}
(Bạn tương tự có thể viết rightOrElse
, mà là một trường hợp sử dụng phổ biến hơn.)
này trở thành cú pháp có thể sử dụng nhiều hơn một chút nếu bạn làm cho nó một phương pháp mở rộng, bằng cách sử dụng implicits.
implicit class EitherOps[A, B](e1: Either[A, B]) {
def leftOrElse(e2: => Either[A, B]): Either[A,B] = // as above
}
Bởi vì đây hy vọng Either[A, B]
cho cả hai toán hạng, thay vì A
hoặc B
(hoặc một số siêu kiểu đó), bạn có thể chuỗi Either
của bạn.
scala> Right[String, Int](2) leftOrElse Right[String, Int](4) leftOrElse Left[String, Int]("Error")
res1: Either[String,Int] = Left(Error)
Điều này trông giống như một cách đặc biệt tối nghĩa để có được hành vi dễ hiểu. Tại sao không chỉ viết nó một cách khác biệt thay vì cố gắng để shoehorn hành vi mong muốn của bạn vào những phương pháp? –