web-dev-qa-db-fra.com

Quel est le but des attributions de types 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 dans le but. À part "faire passer varargs", à quoi servirais-je? Vous trouverez ci-dessous un 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
69
davetron5000

L'attribution de type indique simplement au compilateur quel type vous attendez d'une expression, parmi tous les types valides possibles.

Un type est valide s'il respecte les contraintes existantes, telles que les déclarations de variance et de type, et que ce soit l'un des types d'expression à laquelle il s'applique " est un ", ou bien une conversion qui s'applique dans la portée.

Donc, Java.lang.String extends Java.lang.Object, donc toute String est aussi une Object. Dans votre exemple, vous avez déclaré que vous souhaitiez que l'expression s soit traitée comme une Object et non une String. Puisqu'il n'y a pas de contrainte empêchant cela et que le type souhaité est l'un des types s est un , cela fonctionne.

Maintenant, pourquoi voudriez-vous cela? Considère 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 corrigé cela en tapant le type ascripting s dans la déclaration ss ou vous auriez pu déclarer le type de ss à Set[AnyRef].

Cependant, les déclarations de type obtiennent le même résultat uniquement si vous attribuez une valeur à un identificateur. Ce que l'on peut toujours faire, bien sûr, si on ne s'inquiète pas de mélanger le code avec des identifiants uniques. Par exemple, les éléments suivants ne sont pas compilés:

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

Mais cela fait:

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 idiot d'utiliser un identifiant ici à la place de Nil. Et bien que je puisse simplement écrire List[String]() à la place, 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 référence, voici ce que Scala 2.7 spec (version du 15 mars 2009) a à dire à propos de l'attribution de type:

Expr1 ::= ...
        | PostfixExpr Ascription

Ascription ::= ‘:’ InfixType
             | ‘:’ Annotation {Annotation}
             | ‘:’ ‘_’ ‘*’
73
Daniel C. Sobral

Une possibilité est lorsque les trucs de niveau réseau et protocole série, alors ceci:

val x = 2 : Byte

est beaucoup plus propre que

val x = 2.asInstanceOf[Byte]

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

27
Kevin Wright

L'inférence de type: nous pouvons sauter explicitement le nom du type de quelque chose dans le code source, appelé Inférence de type (bien que requis dans des cas exceptionnels).

Attribution de type: Etre explicite sur le type de quelque chose s'appelle une assignation de type.

ex: val x = 2: octet

voir aussi: 1. Nous pouvons explicitement donner le type de retour à nos fonctions

def t1 : Option[Option[String]] = Some(None)

> t1: Option[Option[String]]

Une autre façon de déclarer cela pourrait être:

def t2 = Some(None: Option[String])
> t2: Some[Option[String]]

Ici, nous n'avons pas donné explicitement le type de retour Option[Option[String]] et le compilateur l'a déduit en tant que Some[Option[String]]. Pourquoi Some[Option[String]] est-ce parce que nous avons utilisé l'attribution de type dans la définition.

  1. Une autre façon d'utiliser la même définition est la suivante:

    def t3 = Some(None)

    > t3: Some[None.type]

Cette fois, nous n'avons rien dit explicitement au compilateur (ni cette définition). Et cela a déduit notre définition en tant que Some [None.type]

0
Vikas Sharma

Vous pouvez trouver ce fil éclairant, si un peu compliqué à suivre. Il est important de noter que vous ajoutez des indicateurs de contrainte au vérificateur de type - cela vous donne un peu plus de contrôle sur le déroulement de la phase de compilation.

0
Justin W

J'utilise l'attribution de type au papier sur les trous de l'inférence de type de Scala. Par exemple, foldLeft sur une collection de type A prend un élément initial de type B et une fonction (B, A) => B utilisée pour plier les éléments de la collection dans l'élément initial. La valeur réelle du type B est déduite du type de l'élément initial. Comme Nil étend la liste [Nothing], son utilisation en tant qu'élément initial pose 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 List.empty [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: List.empty [A] est implémenté en tant que 

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

(la source)

C'est effectivement une forme plus verbeuse de Nil: List [A]

0
pkinsky