Подтвердить что ты не робот

Устранение стирания в scala: аргумент типа non-variable не снят, поскольку он устраняется путем стирания

У меня есть последовательность Seq [Any], в которой есть множество объектов (например, String, Integer, List [String] и т.д.). Я пытаюсь просеять список и разбить его на отдельные списки, разбитые на разделы по типу класса. Ниже приведен шаблон, который я использую в коде:

val allApis = mySequence.filter(_.isInstanceOf[String])

Это хорошо работает и не генерирует никаких предупреждений. Однако, когда я пытаюсь сделать то же самое для фильтрации объектов, которые являются списками строк:

val allApis = mySequence.filter(_.isInstanceOf[List[String]])

Я получаю предупреждение, в котором говорится, что аргумент non-variable type String в типе List [String] не отмечен, поскольку он устраняется стиранием. Теперь техника действительно работает, и я могу с комфортом фильтровать последовательность по своему желанию, но мне интересно, что это подходящий способ справиться с предупреждением в идиоматическом ключе, чтобы я знал, что у меня нет серьезной ошибки скрывается в фоновом режиме, ожидая взорваться

4b9b3361

Ответ 1

Он не работает, потому что он будет выбирать List[Double] или любой другой список в дополнение к List[String]. Существует множество способов устранения проблемы, включая перенос любых параметризованных типов в непараметрированный класс case:

case class StringList(value: List[String])

а затем вы можете просто

mySequence.collect{ case StringList(xs) => xs }

чтобы вытащить списки строк (с правильным типом и безопасным типом также).

В качестве альтернативы, если вы хотите не обертывать объекты и хотите быть уверенными, что они имеют правильный тип, вы можете проверить каждый элемент:

mySequence.filter( _ match {
  case xs: List[_] => xs.forall( _ match { case _: String => true; case _ => false })
  case _ => false
})

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

Другая возможность заключается в склеивании TypeTag ко всему в вашем списке; это не позволит вам вручную обернуть вещи. Например:

import scala.reflect.runtime.universe.{TypeTag, typeTag}
def add[A](xs: List[(Any, TypeTag[_])], a: A)(implicit tt: TypeTag[A]) = (a, tt) :: xs
val mySequence = add(add(add(Nil, List(42)), true), List("fish"))
mySequence.filter(_._2.tpe weak_<:< typeTag[List[String]].tpe)

Ответ 2

val v = 1 ::"abc" :: true :: Nil
v : List[Any] = List(1,abc,true) 

тип типа List был унифицирован для наибольшего общего супер-типа элементов в List, который равен Any.

Shapeless - для спасения.

import shapeless._
import HList._

val s = 1 :: "abc" :: true: HNil
s : shapeless.::[Int,shapeless.::[String,shapelsss.::[Boolean,shapeless.HNil]]]
= 1 :: abc :: true :: HNil

С Shapeless HList вы можете получить безопасность времени компиляции для гетерогенного списка. теперь вы можете filter в форме. например.

s.filter[String]