2010-12-14 10 views
5

W poniższym kodzie:Dlaczego Scala promuje listę [Any] na liście [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])) 

tutaj jest wyjście (Scala 2.8.1):

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

Dlaczego numery awansować java.lang.Long? Jak mogę to zrobić, aby zachować swoje typy AnyVal lub uzyskać "pudełkowy" odpowiednik typu AnyRef?

Odpowiedz

13

Myślę, że odpowiedź jest w Section 3.5.3 of the language reference:

  • Byte słabo zgodny Krótki
  • Krótki słabo odpowiada na int
  • Char słabo odpowiada na int
  • Int słabo zgodny Long
  • Długo słabo odpowiada Float
  • Float słabo pasuje do Double

Z tego powodu Scala wnioskuje, że wspólny typ pomiędzy krótki, Int i długi jest długa, a następnie konwertuje bez długich przedmiotów do Longs:

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

Jeśli chcesz korzystać cały łańcuch zgodność słaby, spróbuj:

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) 

I oczywiście powiedzieć, że chcesz List[Any], wystarczy dodać [Any] na wezwanie do 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

Oto dlaczego (budynek na odpowiedź przez PST):

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

Wydaje Scala próbuje określić typ listy, aby być z największych obiektów, które mogą zawierać wszystkie elementy. Na przykład:

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

Tak, obejście sugerowane przez pst jest odpowiedzią.

4

Anferencja typów działa od najbardziej restrykcyjnego typu (np. Nothing) i poszerzanie, aż jeden typ może zawierać wszystko. W przypadku wartości numerycznych oznacza to poszerzenie z Int do Long. Ale teraz, ponieważ połączenie jest skutecznie do List[Long](ls: Long*) wszystkie wartości numeryczne są promowane z góry.

Tak więc, na przykład, wszystkie z nich dają taką samą listę:

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

mianowicie List[Long](1L, 2L, 3L).Teraz, jeśli nie podoba ten problem, należy określić rodzaj listy jako AnyVal lub Any:

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

Edit: PS: jeśli określasz stałą pewnego rodzaju, powinieneś po prostu podać typ (np. (2: Short)) zamiast przesyłać go do tego typu (np. 2.asInstanceOf[Short]).

Powiązane problemy