77 votes

Quel est le but de l'attribution de type dans Scala?

Il n'y a pas beaucoup d'informations dans la spécification sur le type d'attribution, et il n'y a certainement rien là-dedans à propos de son objectif. À part "faire fonctionner les varargs qui passent", à quoi devrais-je utiliser l'attribution de type? Vous trouverez ci-dessous quelques scala REPL pour la syntaxe et les effets de son utilisation.

 scala> val s = "Dave"
s: java.lang.String = Dave

scala> val p = s:Object
p: java.lang.Object = Dave

scala> p.length
<console>:7: error: value length is not a member of java.lang.Object
       p.length
         ^
scala> p.getClass
res10: java.lang.Class[_ <: java.lang.Object] = class java.lang.String

scala> s.getClass
res11: java.lang.Class[_ <: java.lang.Object] = class java.lang.String

scala> p.asInstanceOf[String].length
res9: Int = 4
 

83voto

Daniel C. Sobral Points 159554

Type de nom est juste de dire au compilateur quel type que vous attendez d'une expression, contre tous les types valides.

Un type est valide s'il respecte les contraintes existantes, telles que la variance et les déclarations de type, et il est l'un des types de l'expression qu'il s'applique "est un", ou il y a une conversion qui s'applique dans le champ d'application.

Donc, java.lang.String extends java.lang.Object, par conséquent, toute String est aussi un Object. Dans votre exemple, vous avez déclaré que vous voulez l'expression s à être traité comme un Object, pas un String. Depuis il n'y a pas de contraintes la prévention et le type est l'un des types s est un, il fonctionne.

Maintenant, pourquoi voudriez-vous que? Réfléchissez à ceci:

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)

Vous pourriez aussi avoir résolu ce par type ascripting s à ss déclaration, ou vous pourriez avoir déclaré sss'type Set[AnyRef].

Cependant, les déclarations de type de réaliser la même chose aussi longtemps que vous assignez une valeur à un identificateur. De laquelle on peut toujours le faire, bien sûr, si l'on ne se soucie pas encombrer le code avec one-shot identifiants. Pour exemple, le code suivant ne compile pas:

def prefixesOf(s: String) = s.foldLeft(Nil) { 
  case (head :: tail, char) => (head + char) :: head :: tail
  case (lst, char) => char.toString :: lst
}

Mais ce n':

def prefixesOf(s: String) = s.foldLeft(Nil: List[String]) { 
  case (head :: tail, char) => (head + char) :: head :: tail
  case (lst, char) => char.toString :: lst
}

Il serait stupide d'utiliser un identificateur ici à la place de Nil. Et si seulement je pouvais écrire List[String]() au lieu de cela, ce n'est pas toujours une option. Considérez ceci, par exemple:

def firstVowel(s: String) = s.foldLeft(None: Option[Char]) { 
  case (None, char) => if ("aeiou" contains char.toLower) Some(char) else None
  case (vowel, _) => vowel
}

Pour la référence, c'est ce que Scala de 2,7 spec (15 mars 2009 projet) a à dire sur le type de nom:

Expr1 ::= ...
        | PostfixExpr Ascription

Ascription ::= ‘:' InfixType
             | ‘:' Annotation {Annotation}
             | ‘:' ‘_' ‘*'

28voto

Kevin Wright Points 31665

Une possibilité est lorsque le niveau du réseau et du protocole série, alors ceci:

 val x = 2 : Byte
 

est bien plus propre que

 val x = 2.asInstanceOf[Byte]
 

La deuxième forme est également une conversion d'exécution (non gérée par le compilateur) et pourrait conduire à des conditions de débordement / dépassement de capacité intéressantes.

0voto

Justin W Points 421

Vous pouvez trouver ce fil éclairant, s'il est un peu compliqué à suivre. La chose importante à noter est que vous ajoutez des conseils de contrainte au vérificateur de type - cela vous donne un peu plus de contrôle sur ce que fait cette phase de compilation.

0voto

pkinsky Points 470

J'utilise un type attribution de papier sur les trous dans la Scala est l'inférence de type. Par exemple, foldLeft sur une collection de type A prend un premier élément de type B et une fonction (B, A) => B qui est utilisé à la fois les éléments de la collection dans l'élément initial. La valeur réelle de type B est déduit à partir du type de l'élément initial. Depuis Nil s'étend Liste[Rien], en l'utilisant comme un élément initial provoque des problèmes:

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)

Alternativement, vous pouvez simplement utiliser la Liste.vide[Int] au lieu de Nil:List[Int].

scala> x.foldLeft(List.empty[Int])( (acc,elem) => elem::acc )
res3: List[Int] = List(4, 3, 2, 1)

edit: Liste.vide[A] est mis en œuvre comme

override def empty[A]: List[A] = Nil

(source)

C'est effectivement un plus détaillé forme de Nil:List[A]

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X