Scala ошибка несоответствия типов даже после проверки типа с помощью isInstanceOf - PullRequest
2 голосов
/ 06 марта 2020

У меня есть функция unlist, принимающая в качестве первого аргумента список любого типа:

def unlist(xs: List[Any], ys: List[Any]): List[Any] = ...

, и я вызываю эту функцию для первого элемента внешнего списка, который может или не может быть список списков. Таким образом, сначала мне нужно проверить, является ли этот элемент head списком, и в этом случае я могу вызвать мою функцию unlist. Я делаю это с помощью метода InsintanceOf, например:

...
if (xs.head.isInstanceOf[List[Any]]) unlist(xs.head, ys)

Однако это не компилируется из-за несоответствия типов в xs.head:

Error: type mismatch;
found   : Any
required: List[Any]

Что я делаю не так?


PS : поскольку многие из вас предложили избегать ввода типа Any, я должен указать, что это является частью упражнения по программированию, направленного на выполнение функции как как можно более общий

Ответы [ 2 ]

5 голосов
/ 06 марта 2020

Чтобы проиллюстрировать комментарий Матеуша

isInstanceOf не запоминается

подразумевается, что мы должны были бы следовать asInstanceOf, например,

if (list.head.isInstanceOf[List[_]]) unlist(list.head.asInstanceOf[List[_]])

Сопоставление с образцом, как продемонстрировал Тим, неявно выполняет комбинацию isInstanceOf/asInstanceOf. Также рассмотрите связанный ответ .

Если вы не можете выполнить рефакторинг Any, который является самым слабым типов, возможно, попытайтесь восстановить столько информации о наборе, сколько как можно раньше, возможно, примерно так:

val lists: List[List[_]] = list.collect { case xs: List[_] => xs }
val ints: List[Int] = list.collect { case i: Int => i }
val strings: List[String] = list.collect { case s: String => s }

Обратите внимание, что из-за стирания типа мы не можем легко сделать намного лучше, чем List[List[_]], например, следующее утверждение проходит

val list: List[Any] = List(List("woo", "hoo"), 42, "kerfuffle")
assert(list.head.isInstanceOf[List[Double]])

В этом последнем случае предупреждение компилятора сообщит вам, что type argument Double in type List[Double] (the underlying of List[Double]) is unchecked since it is eliminated by erasure. Обычно не стоит игнорировать такие предупреждения.

2 голосов
/ 06 марта 2020

Как уже упоминалось в комментариях, использование Any, как это, является признаком неправильного выбора дизайна. Но для конкретной проблемы c, которая у вас есть , вы можете изменить if на match следующим образом:

def unlist(xs: List[Any], ys: List[Any]): List[Any] = ???

val xs: List[Any] = ???

xs.head match {
  case l: List[Any] => unlist(l, ???)
  case _ =>
}

match проверяет, что значение head равно List[Any], затем присваивает значение переменной l, которая имеет тип List[Any] и поэтому может использоваться в вызове unlist.

Примечание : Это работает только потому, что вы тестируете List[Any]. Вы не можете проверить список определенного типа c (например, List[Int]), поскольку процесс, называемый стиранием типа, удаляет информацию времени выполнения, которая потребуется для его работы. Компилятор предупредит вас, когда не сможет реализовать match по этой причине.

Реальное решение этого вопроса - исправить конструкцию для использования определенных c типов, а не Any.

...