На этот комментарий к моему предыдущему ответу Я хочу поделиться своим решением с манифестами, используя актеров akka:
import akka.actor._
trait Message
case class Foo(i: Int) extends Message
case class Bar(b: Boolean) extends Message
case class Baz(s: String) extends Message
case class MSG[C](content: C)(implicit m: Manifest[C]) {
def manifest = m
@inline def asMsg[C] = this.asInstanceOf[MSG[C]]
}
class MyActor[C](implicit manifest: Manifest[C]) extends Actor {
private val behaviour: C =*> Unit = {
case foo @ Foo(i) => println(foo) // i: Int
case bar @ Bar(b) => println(bar) // b: Boolean
}
def receive = {
case m: MSG[_] if m.manifest <:< implicitly[Manifest[C]] && behaviour.isDefinedAt(m.asMsg[C].content) => behaviour(m.asMsg[C].content)
case m => println("wrong message : " + m)
}
}
val system = ActorSystem("MySystem")
val myActor = system.actorOf(Props(new MyActor[Message]()), name = "myactor")
myActor ! MSG(Foo(1)) // Foo(1)
myActor ! MSG(Bar(true)) // Bar(true)
myActor ! MSG(Baz("!")) // wrong message : MSG(Baz(!))
myActor ! Foo(2) // wrong message : Foo(2)
myActor ! MSG("?") // wrong message : MSG(?)
system.shutdown
Кроме того, я попытался использовать это с параметризованными типами:
sealed trait Parameterized1[X] // only marker
case class Foo1[X](x: X) extends Parameterized1[X]
case class MSG1[X, Z[X]](content: Z[X])(implicit mX: Manifest[X]) {
def manifestX = mX
@inline def asMsg[A, C[A]] = this.asInstanceOf[MSG1[A, C]]
}
class MyActor1[X, Z[X]](implicit mX: Manifest[X]) extends Actor {
private val behaviour: Z[X] =*> Unit = {
case foo @ Foo1(x: X) => println(foo)
}
def receive = {
case m: MSG1[_, _] if m.manifestX <:< implicitly[Manifest[X]] && behaviour.isDefinedAt(m.asMsg[X, Z].content) => behaviour(m.asMsg[X, Z].content)
case m => println("wrong message : " + m)
}
}
val system1 = ActorSystem("MySystem1")
val myActor1 = system1.actorOf(Props(new MyActor1[Int, Parameterized1]()), name = "myactor1")
myActor1 ! MSG1(Foo1(1)) // Foo1(1)
myActor1 ! MSG1(Foo1("A")) // wrong message : MSG1(Foo1(A))
myActor1 ! Foo1(1) // wrong message : Foo1(1)
system1.shutdown
Или даже с двумя параметрами типа:
sealed trait Parameterized2[X, Y] // only marker
case class Foo2[X, Y](x: X, y: Y) extends Parameterized2[X, Y]
case class Bar2[X, Y](x: X, y: Y) extends Parameterized2[X, Y]
case class MSG2[X, Y, Z[X, Y]](content: Z[X, Y])(implicit mX: Manifest[X], mY: Manifest[Y]) {
def manifestX = mX
def manifestY = mY
@inline def asMsg[A, B, C[A, B]] = this.asInstanceOf[MSG2[A, B, C]]
}
class MyActor2[X, Y, Z[X, Y]](implicit mX: Manifest[X], mY: Manifest[Y]) extends Actor {
private val behaviour: Z[X, Y] =*> Unit = {
case foo @ Foo2(x: X, y: Y) => println(foo)
case bar @ Bar2(x: X, y: Y) => println(bar)
}
def receive = {
case m: MSG2[_, _, _] if m.manifestX <:< implicitly[Manifest[X]] && m.manifestY <:< implicitly[Manifest[Y]] && behaviour.isDefinedAt(m.asMsg[X, Y, Z].content) => behaviour(m.asMsg[X, Y, Z].content)
case m => println("wrong message : " + m)
}
}
val system2 = ActorSystem("MySystem2")
val myActor2 = system2.actorOf(Props(new MyActor2[Int, String, Parameterized2]()), name = "myactor2")
myActor2 ! MSG2(Foo2(1, "A")) // Foo2(1,A)
myActor2 ! MSG2(Foo2(1, true)) // wrong message : MSG2(Foo2(1,true))
myActor2 ! Foo2(1, "A") // wrong message : Foo2(1,A)
myActor2 ! MSG2((1, "A")) // wrong message : MSG2((1,A))
myActor2 ! MSG2(Bar2(2, "B")) // Bar2(2,B)
system2.shutdown