さまざまなオブジェクト(String、Integer、List [String]など)を含むシーケンスSeq [Any]があります。リストをふるいにかけ、クラスタイプに基づいて分割された個別のリストに分割しようとしています。以下は、コードで使用しているパターンです。
val allApis = mySequence.filter(_.isInstanceOf[String])
これはうまく機能し、警告を生成しません。ただし、文字列のリストであるオブジェクトを除外するために同じことをしようとすると:
val allApis = mySequence.filter(_.isInstanceOf[List[String]])
非可変の型引数であるという警告が表示されます。List[String]型のStringは、erasureによって削除されるため、チェックされていません。現在、この手法は実際に機能しており、必要に応じてシーケンスを快適にフィルター処理できますが、深刻なバグがないことを知っているように、慣用的な方法で警告を処理する適切な方法は何ですか?爆破を待っている背景に潜んでいる
List[Double]
またはList[String]
に加えて他のリストを選択するため、機能しません。問題を解決するには、パラメーター化されていないケースクラスでパラメーター化された型をラップするなど、さまざまな方法があります。
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
})
ただし、これでも空のリストがどのタイプであるかはわかりません。
もう1つの可能性は、TypeTag
sをリスト内のすべてに接着することです。これにより、手動で物をラップする必要がなくなります。例えば:
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)
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]