Die Typzuweisung teilt dem Compiler lediglich mit, welchen Typ Sie von einem Ausdruck aus allen möglichen gültigen Typen erwarten.
Ein Typ ist gültig, wenn er vorhandene Einschränkungen wie Varianz- und Typdeklarationen berücksichtigt und entweder einer der Typen ist, auf die der Ausdruck " ist a " angewendet wird , oder wenn eine Konvertierung im Gültigkeitsbereich gilt.
Also, java.lang.String extends java.lang.Object
also ist jeder String
auch ein Object
. In Ihrem Beispiel haben Sie angegeben, dass der Ausdruck s
als Object
und nicht als behandelt werden soll String
. Da dies durch keine Einschränkungen verhindert wird und der gewünschte Typ einer der Typen s
ist , funktioniert a.
Warum willst du das? Bedenken Sie:
scala> val s = "Dave"
s: java.lang.String = Dave
scala> val p = s: Object
p: java.lang.Object = Dave
scala> val ss = scala.collection.mutable.Set(s)
ss: scala.collection.mutable.Set[java.lang.String] = Set(Dave)
scala> val ps = scala.collection.mutable.Set(p)
ps: scala.collection.mutable.Set[java.lang.Object] = Set(Dave)
scala> ss += Nil
<console>:7: error: type mismatch;
found : scala.collection.immutable.Nil.type (with underlying type object Nil)
required: java.lang.String
ss += Nil
^
scala> ps += Nil
res3: ps.type = Set(List(), Dave)
Sie hätten dies auch beheben können, indem Sie s
bei der ss
Deklaration ascripting eingeben, oder Sie hätten den ss
Typ deklarieren können Set[AnyRef]
.
Typdeklarationen erreichen jedoch nur dasselbe, solange Sie einem Bezeichner einen Wert zuweisen. Was man natürlich immer tun kann, wenn man den Code nicht mit One-Shot-Identifikatoren übersät. Folgendes wird beispielsweise nicht kompiliert:
def prefixesOf(s: String) = s.foldLeft(Nil) {
case (head :: tail, char) => (head + char) :: head :: tail
case (lst, char) => char.toString :: lst
}
Aber das tut:
def prefixesOf(s: String) = s.foldLeft(Nil: List[String]) {
case (head :: tail, char) => (head + char) :: head :: tail
case (lst, char) => char.toString :: lst
}
Es wäre dumm, hier anstelle von einen Bezeichner zu verwenden Nil
. Und obwohl ich List[String]()
stattdessen einfach schreiben könnte , ist das nicht immer eine Option. Betrachten Sie dies zum Beispiel:
def firstVowel(s: String) = s.foldLeft(None: Option[Char]) {
case (None, char) => if ("aeiou" contains char.toLower) Some(char) else None
case (vowel, _) => vowel
}
Als Referenz ist dies, was Scala 2.7 spec (Entwurf vom 15. März 2009) über die Typzuweisung zu sagen hat:
Expr1 ::= ...
| PostfixExpr Ascription
Ascription ::= ‘:’ InfixType
| ‘:’ Annotation {Annotation}
| ‘:’ ‘_’ ‘*’
val x: Byte = 2
Ich benutze die Typzuweisung, um über Löcher in Scalas Typinferenz zu schreiben. Zum Beispiel nimmt foldLeft über eine Sammlung vom Typ A ein Anfangselement vom Typ B und eine Funktion (B, A) => B, mit der die Elemente der Sammlung in das Anfangselement gefaltet werden. Der tatsächliche Wert vom Typ B wird aus dem Typ des Anfangselements abgeleitet. Da Nil List [Nothing] erweitert, verursacht die Verwendung als Anfangselement Probleme:
scala> val x = List(1,2,3,4) x: List[Int] = List(1, 2, 3, 4) scala> x.foldLeft(Nil)( (acc,elem) => elem::acc) <console>:9: error: type mismatch; found : List[Int] required: scala.collection.immutable.Nil.type x.foldLeft(Nil)( (acc,elem) => elem::acc) ^ scala> x.foldLeft(Nil:List[Int])( (acc,elem) => elem::acc ) res2: List[Int] = List(4, 3, 2, 1)
Alternativ können Sie auch List.empty [Int] anstelle von Nil: List [Int] verwenden.
scala> x.foldLeft(List.empty[Int])( (acc,elem) => elem::acc ) res3: List[Int] = List(4, 3, 2, 1)
edit: List.empty [A] ist implementiert als
override def empty[A]: List[A] = Nil
(Quelle)
Dies ist effektiv eine ausführlichere Form von Nil: List [A]
quelle
x.foldLeft[List[Int]](Nil)( (acc,elem) => elem::acc )
?Möglicherweise ist dieser Thread aufschlussreich, wenn er etwas kompliziert ist. Es ist wichtig zu beachten, dass Sie der Typprüfung Hinweise zu Einschränkungen hinzufügen. Dadurch haben Sie ein wenig mehr Kontrolle darüber, was diese Kompilierungsphase tut.
quelle
Typinferenz: Wir können die explizite Angabe des Namens des Typs von etwas im Quellcode überspringen, der als Typinferenz bezeichnet wird (obwohl dies in einigen Ausnahmefällen erforderlich ist.)
Typzuschreibung: Die explizite Angabe des Typs von etwas wird als Typzuschreibung bezeichnet. Welchen Unterschied kann es machen?
Beispiel: Wert x = 2: Byte
Siehe auch: 1. Wir können unseren Funktionen explizit den Rückgabetyp geben
def t1 : Option[Option[String]] = Some(None) > t1: Option[Option[String]]
Eine andere Möglichkeit, dies zu erklären, könnte sein:
def t2 = Some(None: Option[String]) > t2: Some[Option[String]]
Hier haben wir den
Option[Option[String]]
Rückgabetyp nicht explizit angegeben und der Compiler hat darauf geschlossenSome[Option[String]]
. Warum,Some[Option[String]]
weil wir in der Definition die Typzuweisung verwendet haben.Eine andere Möglichkeit, dieselbe Definition zu verwenden, ist:
def t3 = Some(None)
> t3: Some[None.type]
Diesmal haben wir dem Compiler nichts explizit mitgeteilt (auch nicht dieses Defi). Und es folgerte unsere Definition als Some [None.type]
quelle