Почему Scala продвигает Список [Любой] в Список [Длинный]? - PullRequest
5 голосов
/ 14 декабря 2010

В следующем коде:

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]))

вот вывод (Scala 2.8.1):

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

Почему числа повышаются до java.lang.Long?Как я могу сделать это так, чтобы они либо сохранили свои AnyVal типы, либо "упаковали" в эквивалентный AnyRef тип?

Ответы [ 4 ]

13 голосов
/ 14 декабря 2010

Я думаю, что ответ находится в Разделе 3.5.3 языкового справочника :

  • Байт слабо соответствует короткому
  • Short слабо соответствует Int
  • Char слабо соответствует Int
  • Int слабо соответствует Long
  • Long слабо соответствует Float
  • Float слабо соответствует Double

Из-за этого Scala делает вывод, что общий тип между Short, Int и Long - Long, а затем преобразует недлинные объекты в Long:

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

Если вы хотите использовать всю цепочку слабого соответствия, попробуйте:

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)

И, конечно, чтобы сказать, что вы хотите List[Any], просто добавьте [Any] к вашему звонку на 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)
4 голосов
/ 14 декабря 2010

Вывод типа работает, начиная с самого ограничительного типа (например, Nothing) и расширяясь, пока один тип не может содержать все.Для числовых значений это означает расширение от Int до Long.Но теперь, поскольку вызов фактически равен List[Long](ls: Long*), все числовые значения повышаются заранее.

Так, например, все они дают один и тот же список:

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

List[Long](1L, 2L, 3L).Теперь, если вам не нравится это поведение, укажите тип списка как AnyVal или Any:

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

Редактировать: PS, если вы указываете константу определенногоtype, вы должны просто указать тип (например, (2: Short)), а не приводить его к этому типу (например, 2.asInstanceOf[Short]).

1 голос
/ 14 декабря 2010
List[Any](0L, 1.asInstanceOf[Int], 2.asInstanceOf[Short])
0 голосов
/ 14 декабря 2010

Вот почему (основываясь на ответе pst):

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

Кажется, Scala пытается определить тип списка для самого большого объекта, который может содержать все элементы.Например,

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

Таким образом, обходной путь, предложенный pst, является ответом.

...