2010-12-14 52 views
5

Dans le code suivant:Pourquoi Scala fait la promotion de List [Any] sur List [Long]?

def test(list: List[Any]): Unit = { 
    list.foreach { 
    v => 
    v match { 
     case r: AnyRef => println(r + ": " + r.getClass.getName) 
     case d: Double => println(d + ": Double") 
     case f: Float=> println(f + ": Float") 
     case b: Byte => println(b + ": Byte") 
     case c: Char => println(c + ": Char") 
     case s: Short => println(s + ": Short") 
     case i: Int => println(i + ": Int") 
     case l: Long=> println(l + ": Long") 
     case b: Boolean => println(b + ": Boolean") 
     case _ => throw new IllegalArgumentException("Unknown type: " + v) 
    } 
    } 
} 

test(List(0L, 1.asInstanceOf[Int], 2.asInstanceOf[Short])) 

ici est la sortie (Scala 2.8.1):

0: java.lang.Long 
1: java.lang.Long 
2: java.lang.Long 

Pourquoi les chiffres sont promus à java.lang.Long? Comment est-ce que je peux faire ceci de sorte qu'ils gardent leurs types AnyVal ou soient "encadrés" au type équivalent AnyRef?

Répondre

13

Je pense que la réponse est Section 3.5.3 of the language reference:

  • Byte est conforme faiblement à court
  • court conforme faiblement à Int
  • Char conforme faiblement à Int
  • Int est conforme faiblement à long
  • Long faiblement conforme à Float
  • Le flotteur est faiblement conforme au double

Pour cette raison, Scala infère que le type commun entre Short, Int et Long est longue et convertit ensuite les objets non-longs Longs:

scala> List(0L, 0, 0: Short) 
res1: List[Long] = List(0, 0, 0) 

Si vous souhaitez utiliser toute la chaîne de conformité faible, essayez:

scala> List(0: Byte, 1: Short, 'c', 3, 4L, 5.0f, 6.0) 
res2: List[Double] = List(0.0, 1.0, 99.0, 3.0, 4.0, 5.0, 6.0) 

Et, bien sûr de dire que vous voulez un List[Any], il suffit d'ajouter [Any] à votre appel à List:

scala> List[Any](0: Byte, 1: Short, 'c', 3, 4L, 5.0f, 6.0) 
res11: List[Any] = List(0, 1, c, 3, 4, 5.0, 6.0) 
1
List[Any](0L, 1.asInstanceOf[Int], 2.asInstanceOf[Short]) 
0

Voici pourquoi (bâtiment de la réponse par pst):

scala> val x = List(0L, 1.asInstanceOf[Int], 2.asInstanceOf[Short]) 
x: List[Long] = List(0, 1, 2) 

Il semble Scala essaie de définir le type de la liste pour être le plus grand objet qui peut contenir tous les éléments. Par exemple,

scala> val x = List(0.asInstanceOf[Short], 1.asInstanceOf[Int], 2.asInstanceOf[Short]) 
x: List[Int] = List(0, 1, 2) 

La solution proposée par pst est donc la solution.

4

L'inférence de type fonctionne en commençant par le type le plus restrictif (par ex. Nothing) et l'élargissement jusqu'à ce qu'un type puisse contenir tout. Pour les valeurs numériques, cela signifie un élargissement de Int à Long. Mais maintenant, puisque l'appel est effectivement à List[Long](ls: Long*) toutes les valeurs numériques sont promus à l'avance.

Ainsi, par exemple, tous ceux-ci donnent la même liste:

List(1, 2: Byte, 3: Long) 
List(1L, 2, 3: Short) 
List(1: Byte, 2: Long, 3: Byte) 

à savoir un List[Long](1L, 2L, 3L).Maintenant, si vous ne l'aimez pas ce comportement, spécifiez le type de la liste comme AnyVal ou Any:

List[Any](1, 2: Byte, 3: Long) 
List.head.asInstanceOf[AnyRef].getClass // java.lang.Integer 

Edit: post-scriptum Si vous spécifiez une constante d'un certain type, vous devez simplement indiquer le type (par exemple (2: Short)) au lieu de le convertir en ce type (par exemple, 2.asInstanceOf[Short]).