Устранение стирания в 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] не отмечен, поскольку он устраняется стиранием. Теперь техника действительно работает, и я могу с комфортом фильтровать последовательность по своему желанию, но мне интересно, что это подходящий способ справиться с предупреждением в идиоматическом ключе, чтобы я знал, что у меня нет серьезной ошибки скрывается в фоновом режиме, ожидая взорваться
Ответы
Ответ 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]