Aynı modülde örtük materyalizasyon
Gibi parametreli bir sınıfım var
class Test[T]{
//...
}
object Test{
implicit def materializeTest[T]: Test[T] = macro impl[T]
def impl[T: c.WeakTypeTag](c: blackbox.Context) = //...
}
Aynı modülden materyalize edilmiş örtük kullanılırsa, bir hata atar:
macro implementation not found
Ancak sorun, tek bir sınıfı ayrı bir modüle çıkarmak, kesinlikle çirkin ve hantal görünüyor. Belki bundan kaçınmak için "iyi bilinen bir çözüm" vardır? Belki şekilsiz burada yardımcı olabilir?
UPD:
scalaVersion in ThisBuild := "2.13.2"
İşte minimal örneğim:
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
object Main {
sealed trait Adt
case object Adt1 extends Adt
case object Adt2 extends Adt
trait Test[Adtt <: Adt] {
def restrict(restrictions: List[Int]): List[Int]
}
object Test {
def apply[Adtt <: Adt](implicit ev: Test[Adtt]): Test[Adtt] = ev
implicit def implicitMaterializer[
Adtt <: Adt
]: Test[Adtt] = macro impl[Adtt]
def impl[Adtt <: Adt: c.WeakTypeTag](
c: blackbox.Context
): c.Expr[Test[Adtt]] = {
import c.universe._
c.Expr[Test[Adtt]](q"""???""")
}
}
def main(args: Array[String]): Unit = {
Test[Adt1.type].restrict(List(1, 2, 3))
}
}
bu aşağıdaki hataya neden olur:
[error] Main.scala:32:9: macro implementation not found: implicitMaterializer
[error] (the most common reason for that is that you cannot use macro implementations in the same compilation run that defines them)
Yanıtlar
Ayrı bir modüle çıkartabilirsiniz Test
ancakTestMacro
çekirdek
import scala.language.experimental.macros
class Test[T]
object Test {
implicit def materializeTest[T]: Test[T] = macro TestMacro.impl[T]
}
implicitly[Test[Int]] // compiles
makrolar
import scala.reflect.macros.blackbox
object TestMacro {
def impl[T: c.WeakTypeTag](c: blackbox.Context) = {
import c.universe._
q"new Test[${weakTypeOf[T]}]"
}
}
Çirkin ya da değil ama makro uygulamalar uygulanmadan önce derlenmelidir.
Bu, Scala 3'te geliştirildi
http://dotty.epfl.ch/docs/reference/metaprogramming/macros.html#defining-a-macro-and-using-it-in-a-single-project
Shapeless, önceden tanımlanmış bazı standart makroları gizler, kendi makrolarınızda yardımcı olamaz.