2013-08-21 32 views
7

Tại sao khi tôi nhập tất cả điều này hoạt động tốt?Scala.Either getOrElse phương pháp

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

nhưng khi tôi nhập trình biên dịch này không thành công?

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

lỗi Compilation:

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

Vì vậy, tôi không thể chuỗi getOrElse gọi phương thức

+0

Đ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? –

Trả lời

8

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].

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 StringLeftProjection[String, Int]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)