如何在通用方法中替换实际类型参数以获取其值参数的最终类型?

弗拉基米尔·马特维耶夫(Vladimir Matveev)

我有一个带有签名的宏,例如

def generateSomething[A] = macro ...

也就是说,它接受类型参数。该类型应为case类,因此apply在其伴随对象中始终具有相应的方法。

这个宏以及其他所有东西都会生成此apply方法的调用,因此,例如,对于此类:

case class A(x: Int, y: String)

将生成以下调用:

A.apply(someFunction[Int], someFunction[String])

someFunctionapply签名中提取用于调用的参数类型

除非A参数化,否则一切都很好

case class A[T](x: Int, y: T)

使用我当前的方法,将为以下内容生成以下内容generateSomething[A[String]]

A.apply[String](someFunction[Int], someFunction[T])

这显然是无效的。

但是,在知道apply所有类型参数之后,我不知道如何获取也就是说,我不知道如何确保

generateSomething[A[String]]

产生

A.apply[String](someFunction[Int], someFunction[String])

而不是上面的那一块。是否有可能?

更新

我认为我应该重新表述这个问题。

假设有一堂课

case class A[T1, ..., Tn](x1: A1, ..., xm: Am)

哪里Ai可以取决于的任意子集Tk例子:

// T1 = T
// A1 = Int, A2 = T
case class B[T](x: Int, y: T)

// T1 = U, T2 = V
// A1 = Map[U, V], A2 = List[V]
case class C[U, V](m: Map[U, V], l: List[V])

// T1 = W
// A1 = W, A2 = W
case class D[W](t: W, u: W)

// No Ts
// A1 = String, A2 = Double
case class E(v: String, w: Double)  // no type parameters at all

我需要编写一个接受类型参数的宏,A并扩展为A.apply具有预处理参数的方法调用:

myMacro[A[U1, ..., Un]]

// expands to

A.apply[U1, ..., Un](preprocess[A1], ..., preprocess[An])

Uk这是代替的实际类型参数Tk例如(使用上面的类):

myMacro[B[String]] -> B.apply[String](preprocess[Int], preprocess[String])

myMacro[C[Int, Double]] -> C.apply[Int, Double](preprocess[Map[Int, Double]], preprocess[List[Double]])

myMacro[D[Long]] -> D.apply[Long](preprocess[Long], preprocess[Long])

myMacro[E] -> D.apply(preprocess[String], preprocess[Double])

您会看到,apply参数类型可以取决于类型参数。尽管这些参数是宏已知的(因为它总是用具体的类型调用),但我不知道如何将这些参数“传递”给apply函数,以使preprocess类型参数正确。

更新2

是我目前所拥有的。

被骗

就像是:

case class X[A](a: A)

object TParamMacro {
  import scala.language.experimental.macros
  import scala.reflect.macros.whitebox.Context

  def m[A](): A = macro mImpl[A]

  def mImpl[A: c.WeakTypeTag](c: Context)(): c.Expr[A] = {
    import c.universe._
    val TypeRef(pre, sym, args) = weakTypeTag[A].tpe
    val t = args.head
    val expr = 
      if (t <:< typeOf[String]) q"""X.apply[$t]("hi")"""
      else if (t <:< typeOf[Int]) q"X.apply[$t](42)"
      else q"X.apply[$t](null)"
    c.Expr[A](expr)
  }
}

object Test extends App {
  Console println TParamMacro.m[X[String]]()
}

更多示例:

object TParamMacro {
  import scala.language.experimental.macros
  import scala.reflect.macros.whitebox.Context

  def m[A](): Any = macro mImpl[A]

  def mImpl[A: c.WeakTypeTag](c: Context)() = {
    import c.universe._
    val TypeRef(pre, sym, args) = weakTypeTag[A].tpe
    val t = args.head
    val expr = if (t <:< typeOf[String]) q"""X.apply[List[$t]](List.apply[$t]("hi"))"""
      else if (t <:< typeOf[Int]) q"X.apply[List[$t]](List.apply[$t](42))"
      else q"X.apply[List[$t]](Nil)"
    expr
  }
}

在哪里

Console println TParamMacro.m[X[String]]()

产量

X(List(hi))

修复要点后进行编辑:

package evaluator

import scala.language.experimental.macros
import scala.reflect.macros.whitebox.Context

object Evaluator {
  def preprocess[T]: T = ???

  def evaluate[A]: Any = macro evaluateImpl[A]

  def evaluateImpl[A: c.WeakTypeTag](c: Context): c.Expr[A] = {
    import c.universe._

    val tpe = weakTypeOf[A]
    val sym = tpe.typeSymbol.asClass

    require(sym.isCaseClass)

    val companionSym = sym.companion
    val companionTpe = companionSym.typeSignature
    val applyMethod = companionTpe.member(TermName("apply")).asMethod

    val paramTypes = applyMethod.paramLists.flatten.map(_.typeSignature)
    Console println s"apply($paramTypes)"

    val TypeRef(_, _, tpeTypeArgs) = tpe

    val from = applyMethod.typeParams
    val to   = tpeTypeArgs
    val arguments = paramTypes map { t =>
      val u = if (from.nonEmpty) t.substituteTypes(from, to) else t
      Console println s"param is $t, subst is $u"
      q"evaluator.Evaluator.preprocess[$u]"
    }

    c.Expr(q"$companionSym.apply[..$tpeTypeArgs](..$arguments)")
  }
}

因此,您只是将“实际类型args”替换为方法的类型参数。在应用程序中,将“ parameter”用于形式参数,将“ argument”用于实际arg是很有用的。

样本:

package evaluator

case class A(x: Int, y: String)

case class B[T](x: Int, y: T)

case class C[U, T](x: Int, y: T, z: U)

object Test extends App {
  Evaluator.evaluate[A]
  Evaluator.evaluate[B[String]]
  Evaluator.evaluate[C[String, List[Int]]]
}

使用

-Xprint:typer

然后

A.apply(evaluator.Evaluator.preprocess[Int], evaluator.Evaluator.preprocess[String]);
B.apply[String](evaluator.Evaluator.preprocess[Int], evaluator.Evaluator.preprocess[String]);
C.apply[String, List[Int]](evaluator.Evaluator.preprocess[Int], evaluator.Evaluator.preprocess[List[Int]], evaluator.Evaluator.preprocess[String])

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何在通用方法中替换实际类型参数以获取其值参数的最终类型?

来自分类Dev

在.NET通用方法中,如何获取实际参数类型

来自分类Dev

对象值参数的通用类型

来自分类Dev

对象值参数的通用类型

来自分类Dev

Java:使用lambda参数获取通用方法的实际类型

来自分类Dev

如何在通用方法中限制参数类型

来自分类Dev

如何在Kotlin中获取经过修饰的泛型参数的实际类型参数?

来自分类Dev

获取通用参数的类型

来自分类Dev

当必需的参数为null时,如何在通用方法中不指定类型参数?

来自分类Dev

获取通用类型的通用参数

来自分类Dev

获取通用类型的通用参数

来自分类Dev

如何获取给定方法的通用参数的类型

来自分类Dev

飞镖,如何使用反射获取方法参数的通用类型?

来自分类Dev

通用方法参数的类型

来自分类Dev

方法参数的通用类型

来自分类Dev

如何从实现类中获取通用接口的类型参数?

来自分类Dev

如何在Kotlin中跳过对通用类型参数的说明?

来自分类Dev

在宏中查找方法参数的实际类型

来自分类Dev

在周围的建议中,如何获取建议方法的参数的“类型参数”

来自分类Dev

如何在通用方法中减少不需要的类型参数?

来自分类Dev

如何在扩展方法中获取“ this”参数的泛型类型参数?

来自分类Dev

如何在扩展方法中获取“ this”参数的泛型类型参数?

来自分类Dev

获取通用参数类型的名称

来自分类Dev

Java通用获取类型参数

来自分类Dev

获取通用参数类型的名称

来自分类Dev

Java通用获取类型参数

来自分类Dev

通用lambda,实际参数的类型推导(自动)

来自分类常见问题

如何访问方法参数的通用类型参数上的注释?

来自分类Dev

通用方法类型参数声明

Related 相关文章

  1. 1

    如何在通用方法中替换实际类型参数以获取其值参数的最终类型?

  2. 2

    在.NET通用方法中,如何获取实际参数类型

  3. 3

    对象值参数的通用类型

  4. 4

    对象值参数的通用类型

  5. 5

    Java:使用lambda参数获取通用方法的实际类型

  6. 6

    如何在通用方法中限制参数类型

  7. 7

    如何在Kotlin中获取经过修饰的泛型参数的实际类型参数?

  8. 8

    获取通用参数的类型

  9. 9

    当必需的参数为null时,如何在通用方法中不指定类型参数?

  10. 10

    获取通用类型的通用参数

  11. 11

    获取通用类型的通用参数

  12. 12

    如何获取给定方法的通用参数的类型

  13. 13

    飞镖,如何使用反射获取方法参数的通用类型?

  14. 14

    通用方法参数的类型

  15. 15

    方法参数的通用类型

  16. 16

    如何从实现类中获取通用接口的类型参数?

  17. 17

    如何在Kotlin中跳过对通用类型参数的说明?

  18. 18

    在宏中查找方法参数的实际类型

  19. 19

    在周围的建议中,如何获取建议方法的参数的“类型参数”

  20. 20

    如何在通用方法中减少不需要的类型参数?

  21. 21

    如何在扩展方法中获取“ this”参数的泛型类型参数?

  22. 22

    如何在扩展方法中获取“ this”参数的泛型类型参数?

  23. 23

    获取通用参数类型的名称

  24. 24

    Java通用获取类型参数

  25. 25

    获取通用参数类型的名称

  26. 26

    Java通用获取类型参数

  27. 27

    通用lambda,实际参数的类型推导(自动)

  28. 28

    如何访问方法参数的通用类型参数上的注释?

  29. 29

    通用方法类型参数声明

热门标签

归档