标签: scala-macros

如何在dotty宏中访问case类的参数列表

我正在尝试在 dotty 中学习元编程。具体编译时间代码生成。我认为通过构建一些东西来学习是一种很好的方法。所以我决定制作一个 CSV 解析器,它将行解析为案例类。我想使用dotty宏来生成解码器

trait Decoder[T]{
  def decode(str:String):Either[ParseError, T]
}

object Decoder {
  inline given stringDec as Decoder[String] = new Decoder[String] {
    override def decode(str: String): Either[ParseError, String] = Right(str)
  }

  inline given intDec as Decoder[Int] = new Decoder[Int] {
    override def decode(str: String): Either[ParseError, Int] =
      str.toIntOption.toRight(ParseError(str, "value is not valid Int"))
  }
  
  inline def forType[T]:Decoder[T] = ${make[T]}

  def make[T:Type](using qctx: QuoteContext):Expr[Decoder[T]] = ???
}
Run Code Online (Sandbox Code Playgroud)

我已经为Int&提供了基本的解码器String,现在我正在寻找def make[T:Type]方法的指导。如何T在此方法中迭代案例类的参数列表?有没有推荐的方法或模式来做到这一点?

reflection scala metaprogramming dotty scala-macros

8
推荐指数
1
解决办法
741
查看次数

如何在 Scala 中使用没有参数的构造函数参数创建 Case Class 的实例?

我正在制作一个通过反射字段值设置的 Scala 应用程序。这工作正常。

但是,为了设置字段值,我需要一个创建的实例。如果我有一个带有空构造函数的类,我可以使用 classOf[Person].getConstructors 轻松做到这一点....

但是,当我尝试使用具有非空构造函数的 Case 类执行此操作时,它不起作用。我拥有所有字段名称及其值,以及我需要创建的对象类型。我可以用我所拥有的以某种方式实例化 Case Class 吗?

我唯一没有的是来自 Case Class 构造函数的参数名称,或者一种在没有参数的情况下创建它然后通过反射设置值的方法。

我们来看例子。

我有以下

case class Person(name : String, age : Int)
class Dog(name : String) {
    def this() = {
        name = "Tony"
    }
}

class Reflector[O](obj : O) {

    def setValue[F](propName : String, value : F) = ...

    def getValue(propName : String) = ...
}

//This works
val dog = classOf[Dog].newInstance()
new Reflector(dog).setValue("name", "Doggy")

//This doesn't
val person = classOf[Person].newInstance //Doesn't work

val ctor …
Run Code Online (Sandbox Code Playgroud)

reflection macros scala case-class scala-macros

7
推荐指数
1
解决办法
1万
查看次数

是否有可能使用宏来实现类似于Scala的@BeanProperty的东西?

我想创建一个注释或特征,在编译时动态地根据现有字段向对象添加方法.虽然我对类级别的东西很感兴趣,但我也会使用字段级注释(或其他更细粒度的东西).

一个较旧的堆栈溢出问题询问了Scala的实现细节,@BeanProperty回答说:"它是一个编译器插件,但宏也可能允许你这样做".鉴于Scala 2.10中的官方(如果是实验性的)宏版本,现在这种功能是否可行?

macros scala scala-macros

7
推荐指数
1
解决办法
337
查看次数

Scala中符号的导入和通配符导入

我有一个表示包,对象和类的符号列表,并希望在宏上下文中导入它们.

对于包和对象,这将意味着通配符导入,对于类,它将意味着"标准"导入.

给定一个List[Symbol]some.package,some.Classsome.Object,我将如何正确导入这些,我怎么能决定是否"标准"或通配符导入,需要使用?

我目前的做法是:

def importPackageOrModuleOrClass(sym: Symbol): Import =
  if (sym.isPackage || sym.isModule) // e. g. import scala._, scala.Predef
    gen.mkWildcardImport(sym)
  else                               // e. g. import java.lang.String
    gen.mkImport(sym.enclosingPackage, sym.name, sym.name) // <--- ?????
Run Code Online (Sandbox Code Playgroud)

包/模块导入有效,但类导入虽然看起来不正确.

import macros scala class scala-macros

7
推荐指数
1
解决办法
303
查看次数

Scala宏:获取要在运行时使用的TypeSymbols列表

有没有一种方法,以返回ListTypeSymbol使用宏包项下的每个类?

我想要实现的是编写一个宏,它给出了与此列表等效的东西:

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

scala> case class MyClass1()
defined class MyClass1

scala> case class MyClass2()
defined class MyClass2

scala> val typeSymbols = List(typeOf[MyClass1].typeSymbol, typeOf[MyClass2].typeSymbol)
typeSymbols: List[reflect.runtime.universe.Symbol] = List(class MyClass1, class MyClass2)
Run Code Online (Sandbox Code Playgroud)

这是我的设置:

我有一个名为的包foo,其中定义了这些包:

trait FooTrait

case class Bar() extends FooTrait 

case class Bar() extends FooTrait
Run Code Online (Sandbox Code Playgroud)

这是我的宏,它获取foo下扩展的类的所有类型符号FooTrait:

def allTypeSymbols_impl[T: c.WeakTypeTag](c: Context)(packageName: c.Expr[String]) = {
  import c.universe._

  // Get package name from the expression tree
  val Literal(Constant(name: String)) = packageName.tree

  // …
Run Code Online (Sandbox Code Playgroud)

macros scala scala-macros

7
推荐指数
1
解决办法
1696
查看次数

在生成的宏方法中使用`this`

这是我上一个问题的后续行动.

我想像下面的代码一样工作.我希望能够生成一个宏生成的方法:

case class Cat()

test[Cat].method(1)
Run Code Online (Sandbox Code Playgroud)

生成方法本身的实现使用宏("吸血鬼"方法):

// macro call
def test[T] = macro testImpl[T]

// macro implementation
def testImpl[T : c.WeakTypeTag](c: Context): c.Expr[Any] = {
  import c.universe._
  val className = newTypeName("Test")

  // IS IT POSSIBLE TO CALL `otherMethod` HERE?
  val bodyInstance = q"(p: Int) => otherMethod(p * 2)"

  c.Expr { q"""
    class $className  {
      protected val aValue = 1

      @body($bodyInstance)
      def method(p: Int): Int = macro methodImpl[Int]

      def otherMethod(p: Int): Int = p
    }
    new …
Run Code Online (Sandbox Code Playgroud)

scala scala-macros

7
推荐指数
1
解决办法
757
查看次数

如何使用宏注释向Scala案例类添加无参数构造函数?

我想回答这个问题.

而不是写:

case class Person(name: String, age: Int) {
  def this() = this("",1)
}
Run Code Online (Sandbox Code Playgroud)

我以为我会使用宏注释来扩展它:

@Annotation
case class Person(name: String, age: Int)
Run Code Online (Sandbox Code Playgroud)

所以我尝试DefDef在宏注释的impl中使用quasiquotes 将新构造函数添加为普通的,如:

val newCtor = q"""def this() = this("", 1)"""
val newBody = body :+ newCtor
q"$mods class $name[..$tparams](..$first)(...$rest) extends ..$parents { $self => ..$newBody }"
Run Code Online (Sandbox Code Playgroud)

但是这会返回一个错误: called constructor's definition must precede calling constructor's definition

有办法解决这个问题吗?我错过了什么?

谢谢你看看,朱利安

constructor scala case-class scala-macros scala-quasiquotes

7
推荐指数
1
解决办法
1707
查看次数

是否有任何技巧可以在定义的同一文件中使用宏?

我有以下代码:

object Macros {

  import scala.language.experimental.macros
  import scala.reflect.macros.blackbox

  def hello(): Unit = macro hello_impl

  def hello_impl(c: blackbox.Context)(): c.Expr[Unit] = {
    import c.universe._
    reify {
      println("Hello World!")
    }
  }
}


object Main {

  def main(args: Array[String]): Unit = {
    Macros.hello()
  }

}
Run Code Online (Sandbox Code Playgroud)

它抛出以下编译错误:

Error:(21, 17) macro implementation not found: hello
(the most common reason for that is that you cannot use macro implementations in the same compilation run that defines them)
    Macros.hello()
                ^
Run Code Online (Sandbox Code Playgroud)

我的问题是:有没有办法"欺骗"编译器,以便在定义它们的同一个文件中使用宏扩展?我的动机如下:我喜欢用Scala编写代码,最近我在网上判断Codeforces中提交了一些问题,而且一些Scala结构变得很慢.所以,我想创建一些宏扩展,以便快速执行这些构造.但我不能提交多个文件.

谢谢!

scala scala-macros scala-2.11

7
推荐指数
1
解决办法
1623
查看次数

列出在宏中实现密封特征的案例类

让我们假设我们有一个密封的特征和一些继承它的案例类:

  sealed trait SomeTrait
  final case class ClassA(somevalue : Int) extends SomeTrait
  final case class ClassB(str : String) extends SomeTrait
  (...)
Run Code Online (Sandbox Code Playgroud)

现在我想让所有这些案例类将特征扩展为集合.我将如何继续这样做?我甚至需要在什么类型的类中引用这些类?weakTypeTag?别的什么?

从一般意义上讲,这类似于Travis Brown在这里对case对象做同样的回答.

我的应用程序上下文:我有一个HTTP服务器和一个继承单个密封特征的case类的给定文件(更确切地说:这个层次结构实现了命令设计模式).现在,我想为每个案例类的HTTP-POST自动创建一个端点,并将传入的数据解析upickle到与该端点对应的案例类.以编程方式我不需要其他任何类/类型.

scala scala-macros

7
推荐指数
0
解决办法
348
查看次数

Scala 3 中的宏注释

以下是三年多前的Macros: The Plan for Scala 3中的一段话:

例如,我们可以定义一个宏注释 @json,将 JSON 序列化器添加到一种类型中。

知道这在 Scala 3 中如何/是否可行吗?

更一般地说,Scala 3 中有什么可以提供“宏注释”功能吗?以下是宏注释 - Scala 2.13的引用:

与以前版本的宏天堂不同,2.0 中的宏注释在以下意义上是正确的:1) 不仅适用于类和对象,而且适用于任意定义,2)允许扩展类来修改甚至创建伴生对象

scala scala-macros scala-macro-paradise scala-3

7
推荐指数
2
解决办法
1071
查看次数