如何在 Scala 3 宏中创建泛型类型的实例?

Chr*_*rle 6 scala metaprogramming scala-macros scala-3

我正在将宏从 Scala 2 移植到 Scala 3。作为其工作的一部分,Scala 2 宏使用默认构造函数创建泛型类型的实例。在 Scala 2 中使用准引用很容易做到这一点,但我在 Scala 3 宏上遇到了困难。这是迄今为止我最好的方法:

import scala.quoted.*

inline def make[A <: AnyRef]: A = ${ makeThat[A] }

private def makeThat[A <: AnyRef : Type](using Quotes): Expr[A] =
  import quotes.reflect.*

  '{ new A().asInstanceOf[A] }
Run Code Online (Sandbox Code Playgroud)

如果没有.asInstanceOf[A],编译器会发出错误消息:

[error] -- [E007] Type Mismatch Error: ...
[error] 17 |  '{ new A() }
[error]    |     ^^^^^^^
[error]    |Found:    Object
[error]    |Required: A
[error]    |
[error]    |where:    A is a type in method makeThat with bounds <: AnyRef
[error] one error found
Run Code Online (Sandbox Code Playgroud)

有没有更好的解决方案,在运行时不会出现沮丧?

编辑:从 Scala 3.0.1 开始,这甚至不再编译。

Jas*_*r-M 6

您可以使用较低级别的反射 API 创建正确的树。

import scala.quoted.*

inline def make[A <: AnyRef]: A = ${ makeThat[A] }

def makeThat[A <: AnyRef : Type](using Quotes): Expr[A] =
  import quotes.reflect.*

  TypeRepr.of[A].classSymbol.map( sym =>
    Apply(Select(New(TypeTree.of[A]), sym.primaryConstructor), Nil).asExprOf[A]
  )
  .getOrElse(???) // not a class, so can't instantiate
Run Code Online (Sandbox Code Playgroud)

尽管您应该检查构造函数是否没有参数。

  • 是的,Scala 3 中的引号和拼接仅允许类型正确的代码,在这种情况下这是不可能的,因为编译器无法知道某些类型“A &lt;: AnyRef”具有哪些构造函数(如果有)。 (4认同)