Почему скаляр считает, что HashMap.toArray возвращает Array[A] вместо Array[(A,B)]?

Я смотрел на определение toArray для хешмапов:

http://www.scala-lang.org/api/current/index.html

Она имеет

toArray: Array[A]
def toArray[B >: (A, B)](implicit arg0: ClassTag[B]): Array[B]

Я не совсем понимаю - первая часть говорит, что вы получаете массив [A], но вторая часть говорит, что вы получаете массив [B]? Я не ожидаю ничего из этого - Array[(A,B)]

Когда я проверяю это сам:

scala> val x = scala.collection.mutable.HashMap[String, Int]()
x: scala.collection.mutable.HashMap[String,Int] = Map()

scala> x.put("8", 7)
res0: Option[Int] = None

scala> x foreach println
(8,7)

scala> x.toArray
res2: Array[(String, Int)] = Array((8,7))

почему это не похоже на ToList?

toList: scala.List[(A, B)]

3 ответа

Решение

В скаладоке есть все тонкие ошибки. Проблема здесь в том, что вы видите "упрощенную" версию сигнатуры метода (предназначенную для передачи основной части сигнатуры и скрытия таких вещей, как CanBuildFrom в map/flatMap методы, которые действительно являются деталями реализации). Упрощение стало немного ошибочным и, похоже, не имеет особого смысла. Если вы нажмете на ссылку "полная подпись", вы увидите, что настоящая подпись выглядит так:

def toArray[B >: (A, B)](implicit arg0: ClassTag[B]): Array[B]

На самом деле это все еще неправильно, поскольку мы, конечно, не можем иметь тип B, где B >: (A, B). Это должно быть больше похоже на:

def toArray[C >: (A, B)](implicit arg0: ClassTag[C]): Array[C]

Проблема в том, что на самом деле есть два Bs: первый из HashMap само объявление класса (HashMap[A, +B]) в то время как другой прибывает из методов toArray определено в его базовом классе TraversableOnce (def toArray[B >: A](implicit arg0: ClassTag[B]): Array[B]). Просто так получилось, что генератору скаладока не удалось дедуплировать два экземпляра B

API, который вы видите в Scaladoc toArray:

def toArray[B >: (A, B)](implicit arg0: ClassTag[B]): Array[B]

Эквивалентно:

def toArray[C >: (A, B)](implicit arg0: ClassTag[C]): Array[C]

Выбор типа переменной B действительно неудачно (и, возможно, даже ошибка в Scaladoc, я не уверен, что вам разрешено это писать).

Это в основном означает, что вы получите массив наиболее определенного супертипа (A,B) для чего ClassTagдоступно.ClassTagтребуется для того, чтобы создатьArray,

Это в основном означает, что если во время компиляции, тип времени выполнения Map вы конвертируете полностью известно, вы получите Array[(A,B)], Тем не менее, если вы подняли Mapгде-то, тип времени выполнения результирующегоArray будет зависеть от типа приведения, а не от типа среды выполнения. Это другое поведение, чем toList и из-за ограничений JVM относительно того, как можно создавать собственные массивы.

Скаладок просто неправ, потому что он наследует toArray от TraversableOnceгде тип коллекции A и возвращаемое значение B, Array[A] вещь осталась от TraversableOnce где A что угодно TraversableOnce пересекает (в данном случае, на самом деле (A,B) для другого определения A а также B); и хотя он заполняет (A,B) должным образом в полной форме, он по-прежнему использует B в качестве новой возвращаемой переменной вместо другой буквы, такой как C,

Вроде запутанно! Это на самом деле должно читать

def toArray[C >: (A,B)](...[C]): Array[C]

и краткая форма должна быть

toArray: Array[(A,B)]

так же, как вы ожидаете.

Другие вопросы по тегам