5

我正在编写宏来将类型描述转换为单例类型:

object Type2String {

  def apply[I]: Witness.Lt[String] = macro Macros.apply[I]

  final class Macros(val c: whitebox.Context) extends MWithReflection {

    import c.universe._

    def apply[A: WeakTypeTag]: Tree = {

      val tt: Type = weakTypeOf[A]
      val str = tt.toString

      // val vv = viz(tt)

      q"shapeless.Witness.mkWitness[$str]($str)"
    }
  }
}

问题是因为 A 只有一个 WeakTypeTag。它无法从泛型类型中提取正确的信息:


  case class ^^[T1, T2]() {

    final val wTSelf = Type2String[^^[T1, T2]]
  }


    val e1 = ^^[Int, String]()

    e1.wTSelf

这给出了错误的见证类型:shapeless.Witness.Aux[String("T1 ^^ T2")]

所以我的问题是:

  1. 是编译时,类型信息应该是完全可见的,为什么 T1 和 T2 被擦除了?

  2. 如何修复此程序,使其提供正确的类型信息:

shapeless.Witness.Aux[String("Int ^^ String")]

?

4

1 回答 1

2

对于第一个问题,@oleg-pyzhcov 非常清楚地指出了问题:你的宏在定义类的时候被扩展了,这里编译器无法知道实际使用的是什么类型。

对于第二个问题,@oleg-pyzhcov 又是对的。确实有一个类似的示例使用隐式来解决您的问题(scala 2.10.2 调用具有泛型类型的“宏方法”不起作用)。

因此,我尝试稍微更改您的代码以成功返回正确的类型:

import scala.reflect.macros.whitebox
import scala.language.experimental.macros
trait Type2String[T] {
  def apply() : Witness.Lt[String]
}

object Type2String {
  implicit def materializeType2String[T]: Type2String[T] = macro impl[T]

  def impl[T: c.WeakTypeTag](c: whitebox.Context): c.Expr[Type2String[T]] = {
    import c.universe._
    val tt: Type = weakTypeOf[T]
    val str = tt.toString
    //val vv = viz(tt) I don't know what is viz(tt)...

    reify {
      () => c.Expr[Witness.Lt[String]](q"shapeless.Witness.mkWitness[$str]($str)").splice
    }
  }
}

然后您必须在类定义中编写更多代码:

case class ^^[T1, T2]()(implicit val type2String: Type2String[^^[T1, T2]]) {
  final val wTSelf = type2String()
}
//or
case class ^^^[T1, T2]() {
  final def wTSelf(implicit type2String: Type2String[^^[T1, T2]]) = type2String()
}

val e1 = ^^[Int, String]()
//val e2 = ^^^[String, Double]()
e1.wTSelf

那就是。

于 2021-04-09T20:16:28.350 回答