简体   繁体   English

将变量从 Scala 中存在类型的 TypeCast 转换为运行时类型

[英]Cast a variable to runtime type from existential typed TypeCast in Scala

This thread addressed how to use TypeTag to get runtime type of type parameters when used with Existential type. 该线程解决了在与Existential类型一起使用时如何使用TypeTag获取类型参数的运行时类型。 Another thread addressed how to cast a variable to its runtime type retrieved from TypeTag . 另一个线程解决了如何将变量转换为从TypeTag检索到的运行时类型。

My question builds on the aforementioned threads (kind of a combination of the two scenarios).我的问题基于上述线程(两种情况的结合)。 Parts of the code is duplicated from the two threads for clarity.为清楚起见,部分代码是从两个线程中复制的。

scala> import scala.reflect.runtime.universe._
import scala.reflect.runtime.universe._

scala> def cast[A](a: Any, tt: TypeTag[A]): A = a.asInstanceOf[A]
cast: [A](a: Any, tt: reflect.runtime.universe.TypeTag[A])A

scala> abstract class Animal[T](implicit tt: TypeTag[T]) {
     |   val ttag = tt
     | }
defined class Animal

scala> case object Dog extends Animal[Int]
defined object Dog

scala> case object Cat extends Animal[String]
defined object Cat

scala> val aa: List[(Animal[_], Any)] = List((Dog, 5), (Cat, "stringgg"), (Dog, 2))                                                                                                               
aa: List[(Animal[_], Any)] = List((Dog,5), (Cat,stringgg), (Dog,2))

scala> aa(0)._1.ttag
res25: reflect.runtime.universe.TypeTag[_] = TypeTag[Int]

scala> aa(1)._1.ttag
res26: reflect.runtime.universe.TypeTag[_] = TypeTag[String]

scala> cast(aa(0)._2, aa(0)._1.ttag)
res27: Any = 5

scala> cast(aa(1)._2, aa(1)._1.ttag)
res28: Any = stringgg

In short, the last two lines: cast(value, TypeTag[_]) always return a value of type Any .简而言之,最后两行: cast(value, TypeTag[_])总是返回Any类型的值。 But my intention is to cast these values to the correct type stored in Dog|Cat.ttag , which, unfortunately, is not TypeTag[Int] or TypeTag[String] but TypeTag[_] due to usage of existential type.但我的意图是将这些值转换为存储在Dog|Cat.ttag中的正确类型,不幸的是,由于existential类型的使用,它不是TypeTag[Int]TypeTag[String]而是TypeTag[_] Is there any solution for it?有什么解决办法吗?

Edit 1:编辑 1:

Despite the field ttag is of type TypeTag[_] , ttag.tpe does have the right "type" (but as an instance of reflect.runtime.universe.Type ).尽管字段ttag的类型为TypeTag[_]ttag.tpe确实具有正确的“类型”(但作为reflect.runtime.universe.Type的实例)。 Is it possible to use the typetag.tpe to cast to the right type?是否可以使用typetag.tpe转换为正确的类型?

你可以改变cast方法, def cast[A](a: Any, tt: TypeTag[_]): A = a.asInstanceOf[A]

val x: Int = cast(aa(0)._2, aa(0)._1.ttag)

pair with path dependent type, you can type cast as following code shows:与路径依赖类型配对,您可以按以下代码显示类型转换:

import languageFeature.existentials

object TestExistential {
  def main(args: Array[String]): Unit = {
    val aa: Array[(Animal[T], T) forSome {type T}] = Array((Dog, 5:Integer), (Cat, "stringgg"), (Dog, 2:Integer))
    aa.foreach(p=>{
      val ani = p._1
      val attr = p._2 // compiler weakness: existential type T is not unify with ani.castType
      assert(ani.attrTyp.isAssignableFrom(attr.getClass))// because of boxing, real type is Integer not Int
      assert(ani.clzTyp.isAssignableFrom(ani.getClass))
      val typedAni:ani.castType = ani.asInstanceOf[ani.castType]
      println(s"$typedAni of type Animal[${ani.attrTyp}] with $attr")
    })
  }

  abstract class Animal[T]{
    type castType = Animal[T]
    val attrTyp: Class[T]
    val clzTyp: Class[castType]
  }

  case object Dog extends Animal[Integer] {
    override val attrTyp: Class[Integer] = classOf[Integer]
    override val clzTyp: Class[Dog.castType] = classOf[Dog.castType]
  }

  case object Cat extends Animal[String] {
    override val attrTyp: Class[String] = classOf[String]
    override val clzTyp: Class[Cat.castType] = classOf[Cat.castType]
  }
}

if typing in scala repl, you can see the reply:如果输入scala repl,可以看到回复:

scala> val typedAni:ani.castType = ani.asInstanceOf[ani.castType]

typedAni: ani.castType = Dog

scala> typedAni

res0: ani.castType = Dog

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM