2015-04-27 20 views
5

Ich lese Functional Programming in Scala, und in Kapitel 04 implementieren die Autoren Option selbst. Nun, bei der Definition der Funktion getOrElse sie verwenden, um eine obere Grenze, die Art von A auf einen übergeordneten Typen zu beschränken (wenn ein richtig verstanden)Scala Option Typ obere Grenze verstehe nicht

So die Definition lautet:

sealed trait Option[+A] { 
    def getOrElse[B >: A](default: => B): B = this match { 
    case None => default 
    case Some(a) => a 
    } 
} 

Also, wenn wir etwas haben, wie

val a = Some(4) 
println(a.getOrElse(None)) => println prints a integer value 
val b = None 
println(b.getOrElse(Some(3)) => println prints a Option[Integer] value 

aOption[Int] hat geben, so würde A Typ Int sein. B wäre Typ Nothing. Nothing ist ein Subtyp von jedem anderen Typ. Das heißt, Option[Nothing] ist ein Untertyp von Option[Int] (wegen Kovarianz), oder?

Aber mit B >: A sagten wir, dass B ein übergeordneter Typ sein muss ?! Wie können wir also eine Int zurück bekommen? Das ist ein bisschen verwirrend für mich ...

Wer kümmert sich darum zu klären?

Antwort

8

Das bedeutet, dass Option [Nothing] ist ein Subtyp von Option [Int] (wegen der Kovarianz), richtig?

Richtig. Option[Nothing] ist ein Option[Int].

Aber mit B>: A haben wir gesagt, dass B ein Supertyp sein muss ?! Wie können wir einen Int zurück bekommen?

Es muss kein Supertyp sein. Es erfordert nur A als unteren gebundenen. Das bedeutet, dass Sie Int weiterhin an getOrElse übergeben können, wenn AInt ist.

Aber das bedeutet nicht, dass Sie Instanzen einer Unterklasse nicht übergeben können. Zum Beispiel:

class A 
class B extends A 
class C extends B 

scala> Option(new B) 
res196: Option[B] = Some([email protected]) 

scala> res196.getOrElse(new C) 
res197: B = [email protected] 

scala> res196.getOrElse(new A) 
res198: A = [email protected] 

scala> res196.getOrElse("...") 
res199: Object = [email protected] 

Ich kann immer noch eine Instanz von C, übergeben, da C up-Cast zu B sein kann. Ich kann auch einen Typ höher in der Vererbungsstruktur übergeben, und getOrElse wird stattdessen diesen Typ zurückgeben. Wenn ich einen Typ übergebe, der nichts mit dem Typ zu tun hat, der in der Option enthalten ist, dann wird der Typ mit der geringsten Obergrenze abgeleitet. Im obigen Fall ist es Any.


Also warum ist die Untergrenze dort überhaupt? Warum nicht haben:

def getOrElse[B <: A](default: => B): B 

Das wird nicht funktionieren, weil getOrElse entweder müssen die A zurück, die B im Option, oder die Standard enthalten ist. Aber wenn wir die A zurückgeben, und A ist kein B, so ist der typgebundene ungültig.Vielleicht, wenn getOrElse zurück A:

def getOrElse[B <: A](default: => B): A 

Dies funktionieren würde (wenn es wirklich so definiert wurde), aber Sie würden durch die Art-Grenzen überschritten werden. In meinem obigen Beispiel konnten Sie also nur B oder C an getOrElse über eine Option[B] übergeben. Auf jeden Fall ist dies nicht in der Standardbibliothek.


Die Standardbibliothek getOrElse ermöglicht es Ihnen, alles zu übergeben. Angenommen, Sie haben Option[A]. Wenn wir einen Untertyp von A übergeben, wird er auf A hochgerechnet. Wenn wir A passieren, ist das offensichtlich in Ordnung. Und wenn wir einen anderen Typ übergeben, dann leitet der Compiler die kleinste obere Grenze zwischen den beiden ab. In allen Fällen ist die typgebundene B >: A erfüllt.

Da getOrElse Ihnen erlaubt, alles zu übergeben, halten viele es für sehr schwierig. Zum Beispiel könnten Sie haben:

val number = "blah" 
// ... lots of code 
val result = Option(1).getOrElse(number) 

Und das wird kompilieren. Wir haben nur eine Option[Any], die wahrscheinlich irgendwo anderswo einen Fehler verursacht.

+0

Vielen Dank, aber könnten Sie bitte ein Beispiel dafür geben, welchen Typ wir nicht an res196.getOrElse übergeben können ... Derzeit sehe ich in diesem Beispiel keine untere Grenze. Oder besser zu sagen, ich verstehe jetzt nicht, was es für einen Typ bedeutet, eine untere Grenze zu sein ... – Marin

+0

@Marin Sie können jeden beliebigen Typ an 'getOrElse' übergeben. Siehe meine Bearbeitung. –

+0

danke! Ich denke, ich verstehe es jetzt. – Marin