Scala 宏:获取参数默认值

2024-03-29

我有下一个代码,我想从值中提取默认参数。

//
def extractor[T] = macro extractorImpl[T]

def extractorImpl[T: c.WeakTypeTag](c: Context) = {
  //first i got a type contructor
  ???
}

我尝试与attachments but attachments.all返回一个Set[Any]与(例如)SymbolSourceAttachment(val name: String = "new name")

SymbolSourceAttachment包含ValDef但我不知道如何从中提取SymbolSourceAttachment ValDef.

顺便说一句,我应该得到一个Map[String, String]("name" -> "new name")

Example:

case class Person(name: String = "new name")

object Macro {
  def extractor[T] = macro extractorImpl[T]

  def extractorImpl[T: c.WeakTypeTag](c: Context) = {
    import c.universe._

    c.weakTypeOf[T].declarations.collect {
      case a: MethodSymbol if a.isConstructor =>
        a.paramss.collect {
          case b => b.collect {
            case c =>
              c.attachments.all {
                case d => println(showRaw(d)) // => SymbolSourceAttachment(val name: String = "new name")  
              }
          }
        }
      }
   } 
}

宏应该返回Map("name" -> "new name")


既然你看到了SymbolSourceAttachment,我假设您正在使用宏天堂(因为它是仅在天堂中使用的内部附件),所以我可以随意使用准引号:)

没有简单的方法可以获取 Scala 反射 API 中的默认参数值。最好的办法是对为计算默认值而创建的方法的名称进行逆向工程,然后引用这些方法。

SymbolSourceAttachment如果你的宏在编译案例类的同一个编译运行中扩展,那么它会起作用,但它会在单独的编译下中断(附件不保存在类文件中),并且它在普通的 Scala 中不起作用(因为这个执着是天堂独有的)。

=== Macros.scala ===

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

object Macros {
  def impl[T](c: Context)(T: c.WeakTypeTag[T]): c.Expr[Map[String, Any]] = {
    import c.universe._
    val classSym = T.tpe.typeSymbol
    val moduleSym = classSym.companionSymbol
    val apply = moduleSym.typeSignature.declaration(newTermName("apply")).asMethod
    // can handle only default parameters from the first parameter list
    // because subsequent parameter lists might depend on previous parameters
    val kvps = apply.paramss.head.map(_.asTerm).zipWithIndex.flatMap{ case (p, i) =>
      if (!p.isParamWithDefault) None
      else {
        val getterName = newTermName("apply$default$" + (i + 1))
        Some(q"${p.name.toString} -> $moduleSym.$getterName")
      }
    }
    c.Expr[Map[String, Any]](q"Map[String, Any](..$kvps)")
  }

  def extractor[T]: Map[String, Any] = macro impl[T]
}

=== Test.scala ===

case class C(x: Int = 2, y: String, z: Boolean = true)(t: String = "hello")

object Test extends App {
  println(Macros.extractor[C])
}

17:10 ~/Projects/Paradise2103/sandbox/src/main/scala (2.10.3)$ scalac Macros.scala && scalac Test.scala && scala Test
Map(x -> 2, z -> true)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Scala 宏:获取参数默认值 的相关文章

  • 使用Scala宏生成方法

    我想在 Scala 2 11 中使用注释宏生成方法的别名 我什至不确定这是否可能 如果是 怎么办 示例 鉴于下面的内容 我希望注释宏扩展到 class Socket alias aliases Seq ask read def load n
  • Scala:在编译时验证类参数不是instanceOf特征

    在编译时 我想验证类参数不是特定特征 T 的实例 我知道如何在运行时使用require or a case match但想知道如何在编译时完成此操作以防止用户提供某种类型的对象混合 我研究过 scala 宏 反射 但无法完全理解它 trai
  • 如何将scala代码块转换为字符串?

    我需要实现一个测试函数 用于检查 splain 插件的编译时错误信息 该函数的一部分需要将代码块转换为字符串 例如 def convert fn gt Unit String for testing val code convert obj
  • 如何使用宏为 Scala 案例类中的每个字段生成案例对象?

    我正在尝试生成case objects 代表每个case member每个孩子的case class具有密封特征 我能够在宏中生成代码 但我不知道如何在我的代码中使用它 示例用例 sealed trait Item sealed trait
  • Scala 宏:定义顶级对象

    我看了type macros对于斯卡拉 但是当我想从示例创建对象时 我收到错误 Example scala 7 gt or lt expected type Test url String macro impl Example scala
  • 在多阶段编译中,我们是否应该使用标准的序列化方法来通过阶段传送对象?

    这个问题是在 Scala 3 Dotty 中提出的 但应该推广到 MetaML 系列之外的任何语言 Scala 3 宏教程 https docs scala lang org scala3 reference metaprogramming
  • 隐式宏。默认隐式值。如何?

    我什至不知道如何问这个问题 我有一个宏可以创建一个实例IsEnum T 对于一个类型T 我正在对其进行测试 并希望确保对于未密封的类型或通常不满足枚举要求的类型找不到隐式类型 所以我创建了这个方法来测试 def enumOf T impli
  • Scala 宏检查树的匿名函数

    我刚刚开始使用宏 感觉我错过了一些非常明显的痛苦 我想检查 AST 中是否有传递给我的宏的匿名 lambda 函数 最终我想对它做一些事情 但我在第一个障碍上就失败了 我的代码如下所示 object Test extends App doI
  • StringContext 和宏:一个简单的示例

    我正在努力实现一个StringContext扩展名允许我这样写 val tz zone Europe London tz is of type java util TimeZone 但附加的警告是如果提供的时区无效 它应该无法编译 假设可以
  • Scala / Dotty - 将特征混合到现有对象中

    有没有办法将特征混合到 Dotty 或 Scala 中的现有对象中 class SomeClass trait SomeTrait This works but it s not what I m looking for new SomeC
  • 如何在 reify 子句中使用 Scala 宏中计算的类型?

    我一直在使用 Scala 宏 并在宏中包含以下代码 val fieldMemberType fieldMember typeSignatureIn objectType match case NullaryMethodType tpe gt
  • Scala 宏的静态返回类型

    所以我有这个宏 import language experimental macros import scala reflect macros Context class Foo class Bar extends Foo def laun
  • 如何获取Scala函数的参数/返回类型?

    我有一个函数 想要获取它的参数类型和返回类型以在 Scala 宏中使用 scala gt val fn a String b Double gt 123 fn String Double gt Int
  • 当宏注释不能在定义它的同一编译中使用时,这意味着什么?

    我对这个说法很好奇 错误 3 18 另一种可能性是您尝试使用宏 定义它的同一编译运行中的注释 我尝试谷歌搜索并发现了这个 最后 请记住 使用宏需要分两步进行编译 首先编译宏 然后编译使用宏的代码 这是必要的 以便您的宏可以在编译其余代码之前
  • 如何调试宏注释?

    背景 我正在尝试添加一个 PrismsMonocle 的注释将按如下方式工作 鉴于 Prisms sealed trait Foo case object A extends Foo case object B extends Foo 它将
  • 获取密封特征的子类

    是否有可能 通过宏 某种形式的无形状自动魔法或其他形式 获得密封特征的子类列表 在编译时 在运行时 您不需要任何第三方库来执行此操作 sealed trait MyTrait case object SubClass1 extends My
  • 是否可以定义带有可变参数的宏,并获取每个参数的类型?

    下面是一个明显的可变参数函数 def fun xs Any 我们可以用类似的方式定义一个宏 def funImpl c Context xs c Expr Any fun 1 1 1 0 但在本例中 所有参数都键入为Any 事实上 编译器在
  • Scala:在运行时替换方法

    假设我有课 class Original def originalMethod 1 现在 假设我有一个例子 val instance new Original 现在是否可以做点什么instance在运行时替换originalMethod用不
  • 如何在Scala3中编译并在运行时执行scala代码?

    我想使用 Scala3 编译并执行在运行时以字符串形式给出的 Scala 代码 例如在 Scala 2 中我会使用 Reflection import scala reflect runtime universe as ru import
  • 如何用其他树替换子树?

    在 Scala 宏中 我想做这样的事情 我有一个Tree 可能很大 现在我想找到这棵树的一个具有某种具体形式的子树 例如Apply 现在我想创建一棵新树 它是原始树的副本 但找到的子树被其他树替换 例如 通过类似的方法 我可以用调用某些其他

随机推荐