3

假设,我向一个actor发送一个请求并同步接收它的响应:

case class MyRequest()
case class MyResponse(data:Any)

val resp = myActor !? MyRequest()

现在我必须沮丧resp才能MyResponse访问data

val data = (resp.asInstanceOf[MyResponse]).data

如何摆脱强制转换并以类型安全的方式编写代码?(我想我可以改用模式匹配,但我更喜欢另一种解决方案)。

4

4 回答 4

4

据我所知,Scala Actors 没有类型。所以使用支持类型化actors的Akkaactors 。我之前也遇到过你的问题,并用隐式清单处理了它,以便在 scala 中获得某种类型的演员。

于 2011-06-19T20:05:04.683 回答
3

模式匹配是从消息中获取数据并区分您收到的消息类型的常规方法。

我只会在这里使用模式匹配,并且很好奇您为什么更喜欢另一种解决方案。

于 2011-06-19T20:16:28.820 回答
3

演员没有类型,所以没有办法用核心库来做。但是,有几种方法可以为其创建实用方法。

您可以在消息中对结果类型进行编码,然后使用一个实用方法来使用它:

trait Result[T]

class RichActor(self: Actor) {
    def !?![T](msg: Result[T]): T = (self !? msg).asInstanceOf[T]

    def !?![T](timeout: Long, msg: Result[T]) = (self.!?(timeout, msg)).asInstanceOf[Option[T]]
}

implicit def enrichActor(a: Actor) = new RichActor(a)

用法:

case class Message() extends Result[Int]

val i = actor !?! Message()

i 的类型是 Int

注意:以前在这里发布:http ://www.tikalk.com/java/blog/type-safe-actor-messages

于 2011-06-19T20:20:15.587 回答
1

在对我之前的答案的评论中,我想使用 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
于 2012-09-15T08:45:59.487 回答