Scala asInstanceOf with parameterized types

前端 未结 5 1214
清歌不尽
清歌不尽 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 14:53

    Unfortunately, this in an inherent limitation of asInstanceOf. I'm actually surprised to see the scaladoc mention it in details:

    Note that the success of a cast at runtime is modulo Scala's erasure semantics. Therefore the expression 1.asInstanceOf[String] will throw a ClassCastException at runtime, while the expression List(1).asInstanceOf[List[String]] will not. In the latter example, because the type argument is erased as part of compilation it is not possible to check whether the contents of the list are of the requested type.

    If you're mainly concerned about failing fast on wrong cast for traversable which would likely be the main issue when getting stuff back from your DB/memcached interface, I was playing around forcing a cast of the head for traversable objects:

    def failFastCast[A: Manifest, T[A] <: Traversable[A]](as: T[A], any: Any) = { 
      val res = any.asInstanceOf[T[A]]
      if (res.isEmpty) res 
      else { 
        manifest[A].newArray(1).update(0, res.head) // force exception on wrong type
        res
      }
    }
    

    On a simple example it works:

    scala> val x = List(1, 2, 3): Any
    x: Any = List(1, 2, 3)
    
    scala> failFastCast(List[String](), x)
    java.lang.ArrayStoreException: java.lang.Integer
    [...]
    
    scala> failFastCast(List[Int](), x)
    res22: List[Int] = List(1, 2, 3)
    

    But not on a more complex one:

    val x = Map(1 -> ("s" -> 1L)): Any
    failFastCast(Map[Int, (String, String)](), x) // no throw
    

    I wonder if there is a way to recursively drill down into A to keep casting until there is no more type parameters...

提交回复
热议问题