【问题标题】:TypeTag for case classes案例类的 TypeTag
【发布时间】:2017-09-05 20:31:31
【问题描述】:

我想创建一个案例类Bla,它接受一个类型参数A,它在运行时知道A 的类型(它将它存储在它的info 字段中)。

我的尝试如下例所示。问题是这个例子没有编译。

case class Bla[A] (){
  val info=Run.paramInfo(this) // this does not compile
}
import scala.reflect.runtime.universe._

object Run extends App{
  val x=Bla[Int]
  def paramInfo[T](x:T)(implicit tag: TypeTag[T]): String = {
    val targs = tag.tpe match { case TypeRef(_, _, args) => args }
    val tinfo=s"type of $x has type arguments $targs"
    println(tinfo)
    tinfo
  }
  paramInfo(x)
}

但是,当我评论 val info=Run.paramInfo(this) 时,程序运行良好并打印:

Bla() 的类型具有类型参数 List(Int)

有没有办法让下面的这个例子编译? (或者以其他方式实现相同的目标,即一个案例类是自我意识到它的类型参数的类型?)

【问题讨论】:

    标签: scala reflection case-class scala-reflect reify


    【解决方案1】:

    为此使用基于反射的 API 没有什么意义,shapeless 有一个类型类,它使用隐式宏向运行时公开编译时间信息。

    import shapeless.Typeable
    
    
    class Test[T : Typeable] {
      def info: String = implicitly[Typeable[T]].describe
    }
    

    在这里滚动你自己的东西也相对容易,但不得不在不同的编译单元中编译隐式宏而不是使用它的任何编译单元都带来了额外的不便。

    【讨论】:

    • 谢谢,info 的值不是在使用TypeTag 时在编译时确定的吗?
    • @jhegedus 不,TypeTag 是反射 API 的东西,它是 java 的 Class[_] 的更进化版本。
    • TypeTag 的值似乎是在编译时决定的:“像 scala.reflect.Manifest 一样,TypeTags 可以被认为是携带编译时可用的所有类型信息到运行时的对象. 例如,TypeTag[T] 封装了一些编译时类型 T 的运行时类型表示。但是请注意,TypeTags 应该被认为是对 2.10 之前的 Manifest 概念的更丰富的替代,它还完全集成了斯卡拉反射。” docs.scala-lang.org/overviews/reflection/…
    【解决方案2】:

    你只需要将隐式类型标签参数传递给case类构造函数(否则在调用paraInfo需要它之前类型信息会丢失):

    case class Bla[A : TypeTag]() { ... }
    

    简写为:

    case class Bla[A](implicit tag: TypeTag[A]) { ... }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-06-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多