2013-08-21 6 views
7

Perché quando si digita questo funziona tutto bene?Scala.El metodo getOrElse

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

ma quando si digita questa compilazione non riesce?

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

errore di compilazione:

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

Quindi non posso catena getOrElse chiamata di metodo

+0

Questo sembra un modo particolarmente oscuro per ottenere un comportamento di caduta abbastanza semplice. Perché non scriverlo in modo diverso invece di provare a calzare il tuo comportamento desiderato in questi metodi? –

risposta

8

La firma di getOrElse per un LeftProjection[A, B] è:

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

vale a dire che si aspetta che il argomento per essere di tipo AA che è un supertipo di A.

Nel primo esempio, hai omesso le annotazioni di tipo, consentendo al compilatore di dedurre Nothing per A. Quindi, hai fornito un argomento di tipo LeftProjection[Nothing, Int].

Perché Nothing è un sottotipo di tutti i tipi , LeftProjection[Nothing, Int] è banalmente un supertipo! Questo caso speciale nel sistema di tipi significa che è stato controllato quasi per caso.

Tuttavia, il supertipo più specifico di String e LeftProjection[String, Int] è Serializable.


Quindi, se si vuole catena Either s, è necessario un metodo che può prendere un altro Either[A, B], non solo un A o B.

Il metodo sembra che tu voglia sarebbe simile a questa:

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 
    } 

(Si potrebbe analogamente scrivere rightOrElse, che è un caso d'uso più comune.)

Questo diventa sintatticamente un po 'più utilizzabile se lo fai un metodo di estensione, usando impliciti.

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

Perché questo si aspetta Either[A, B] per entrambi gli operandi, invece di A o B (o qualche supertipo della stessa), è possibile concatenare le vostre Either s.

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