Scala asInstanceOf with parameterized types

前端 未结 5 1228
清歌不尽
清歌不尽 2020-12-02 14:17

I would like to write a function that casts to type A, where A can be e.g. List[Int], or a more complicated parameterized type like Map[Int, List[Int]].

def          


        
5条回答
  •  陌清茗
    陌清茗 (楼主)
    2020-12-02 15:10

    You are indeed correct - type erasure means that you cannot "cast" in such a way as to distinguish between List[Int] and List[String], for example. However, you can improve on the cast which you are performing, whereby A is erased in such a way as to mean that you cannot distinguish between an Int and a String:

    def cast[A](a : Any) = a.asInstanceOf[A]
    //... is erased to
    def erasedCast(a : Any) = a.asInstanceOf[Any]
    

    What you need are reified generics, using manifests

    def cast[A <: AnyRef : Manifest](a : Any) : A 
      = manifest[A].erasure.cast(a).asInstanceOf[A]
    

    Whilst the final cast is erased to AnyRef, at least you should have the correct Class[_] instance (manifest.erasure) to get the top level type correct. In action:

    scala> cast[String]("Hey")
    res0: String = Hey
    
    scala> cast[java.lang.Integer]("Hey")
      java.lang.ClassCastException
        at java.lang.Class.cast(Class.java:2990)
        at .cast(:7)
        at .(:9)
    
    scala> cast[List[String]](List("Hey"))
    res2: List[String] = List(Hey)
    
    scala> cast[List[Int]](List("Hey"))
    res3: List[Int] = List(Hey)
    

    My advice is not to use nested reflection to decide whether the target was really a List[Int]: this is not generally feasible. For what should the following return?

    cast[List[Int]](List[AnyVal](1, 2))
    

提交回复
热议问题