Diese werden als allgemeine Typeinschränkungen bezeichnet . Sie ermöglichen es Ihnen, innerhalb einer typparametrisierten Klasse oder Eigenschaft eine ihrer Typparameter weiter einzuschränken . Hier ist ein Beispiel:
case class Foo[A](a:A) { // 'A' can be substituted with any type
// getStringLength can only be used if this is a Foo[String]
def getStringLength(implicit evidence: A =:= String) = a.length
}
Das implizite Argument evidence
wird vom Compiler bereitgestellt, iff A
ist String
. Sie können als daran denken Beweis , dass A
ist String
--die Argument selbst ist nicht wichtig, nur zu wissen , dass es existiert. [edit: Nun, technisch gesehen ist es tatsächlich wichtig, weil es eine implizite Konvertierung von A
nach darstellt String
, was es dir ermöglicht, aufzurufen a.length
und den Compiler dich nicht anschreien zu lassen]
Jetzt kann ich es so benutzen:
scala> Foo("blah").getStringLength
res6: Int = 4
Aber wenn ich es mit einem Foo
anderen als einem String
:
scala> Foo(123).getStringLength
<console>:9: error: could not find implicit value for parameter evidence: =:=[Int,String]
Sie können diesen Fehler lesen als "konnte keinen Beweis dafür finden, dass Int == String" ... das ist, wie es sein sollte! getStringLength
legt weitere Beschränkungen für die Art fest, A
als dies Foo
im Allgemeinen erforderlich ist; Sie können nämlich nur getStringLength
auf a aufrufen Foo[String]
. Diese Einschränkung wird zur Kompilierungszeit erzwungen, was cool ist!
<:<
und <%<
arbeiten ähnlich, aber mit geringfügigen Abweichungen:
A =:= B
bedeutet, dass A genau B sein muss
A <:< B
bedeutet, dass A ein Subtyp von B sein muss (analog zur einfachen Typbeschränkung <:
)
A <%< B
bedeutet, dass A als B angezeigt werden muss , möglicherweise durch implizite Konvertierung (analog zur einfachen Typbeschränkung <%
).
Dieses Snippet von @retronym ist eine gute Erklärung dafür, wie so etwas früher erreicht wurde und wie allgemeine Typeinschränkungen es jetzt einfacher machen.
NACHTRAG
Um Ihre Folgefrage zu beantworten, ist das Beispiel, das ich gegeben habe, zugegebenermaßen ziemlich erfunden und offensichtlich nicht nützlich. Stellen Sie sich vor, Sie definieren damit eine List.sumInts
Methode, die eine Liste von Ganzzahlen zusammensetzt. Sie möchten nicht zulassen, dass diese Methode für eine alte Methode aufgerufen wird, sondern List
nur für eine List[Int]
. Der List
Typkonstruktor kann jedoch nicht so eingeschränkt werden. Sie möchten weiterhin Listen mit Zeichenfolgen, Foos, Balken und Dingsbums haben können. Wenn Sie also eine allgemeine Typeinschränkung festlegen sumInts
, können Sie sicherstellen, dass nur diese Methode eine zusätzliche Einschränkung aufweist, die nur für a verwendet werden kann List[Int]
. Im Wesentlichen schreiben Sie Sonderfallcode für bestimmte Arten von Listen.