我想在运行时定义一个案例类,例如
val tb = universe.runtimeMirror(getClass.getClassLoader).mkToolBox()
val myClass: ClassDef = q"case class Authentication(email: String)".asInstanceOf[ClassDef]
val definedClass = tb.define(myClass)
然后能够在另一个反思中引用它
// Actor code that recognise the defined case object
val actorCode = q"""
import akka.actor._
object HelloActor {
def props() = Props(new HelloActor())
}
class HelloActor() extends Actor {
def receive = {
case $definedClass(emailParam) => println("case object instance has been received!")
case _ => println("None received!")
}
}
return HelloActor.props()
"""
知道如何做到这一点吗?
您显示的示例无需任何编译时反射即可实现:
import akka.actor._
// define extractor object: https://docs.scala-lang.org/tour/extractor-objects.html
sealed trait EmailExtractor[A] {
def unapply(value: A): Option[String]
}
object EmailExtractor {
def of[A](pf: PartialFunction[A, String]) = new EmailExtractor[A] {
def unapply(value: A): Option[String] = pf.lift(value)
}
}
// inject difference in behavior via constructor
class HelloActor[A](emailExtractor: EmailExtractor[A]) extends Actor {
def receive = {
case emailExtractor(emailParam) =>
println("case class instance has been received!")
case _ => println("None received!")
}
}
object HelloActor {
def props[A](emailExtractor: EmailExtractor[A]) =
Props(new HelloActor(emailExtractor))
}
implicit val actorSystem: ActorSystem = ActorSystem()
// you'd have to define message somewhere available to both:
// * actor you are creating
// * place where you are sending a message
// anyway, there is no reason to generate a whole new actor because of it
def oneTimeCaseClass1 = {
case class Message(email: String)
actorSystem.actorOf(HelloActor.props(EmailExtractor.of[Message] {
case Message(string) => string
})) ! Message("[email protected]")
}
def oneTimeCaseClass2 = {
case class Message(email: String)
actorSystem.actorOf(HelloActor.props(EmailExtractor.of[Message] {
case Message(string) => string
})) ! Message("[email protected]")
}
oneTimeCaseClass1
oneTimeCaseClass2
scala.concurrent.Await.result(
actorSystem.terminate(),
scala.concurrent.duration.Duration.Inf
)
(参见scastie)
另外:
return
是一种糟糕的代码实践你的代码看起来几乎没问题。
您刚刚错过了
.companion
中的
val actorCode = q"""
import akka.actor._
object HelloActor {
def props() = Props(new HelloActor())
}
class HelloActor() extends Actor {
def receive = {
case ${definedClass.companion}(emailParam) => println("case object instance has been received!")
case _ => println("None received!")
}
}
ActorSystem("hellokernel").actorOf(HelloActor.props()) ! ${definedClass.companion}("abc")
"""
tb.eval(actorCode) // case object instance has been received!
斯卡拉 2.13.8