我有一些(Akka)演员代码使用案例类+复制构造函数来更新状态:
def foo(state:StateCaseClass) : Receive = {
import state._
{
case Bar(updates) =>
context become foo(copy(/* change a limited number of things */))
// ... other message processing w/ lots of context become foo(copy(...))
}
}
我想在导入
下面添加def update = context become foo(copy(_))
以便代码可以
def foo(state:StateCaseClass) : Receive = {
import state._
def update = context become foo(copy(_))
{
case Bar(updates) =>
update(/* change a limited number of things */)
// ... etc
}
}
但是没有编译。我当然可以稍微调整def update
来摆脱大部分样板,但copy
仍然存在:
def foo(state:StateCaseClass) : Receive = {
import state._
def update(newState:StateCaseClass) = context become foo(newState)
{
case Bar(updates) =>
update(copy(/* change a limited number of things */))
// ... etc
}
}
是否有类似的语法可以让我通过args传递给case类复制构造函数并干掉最后一位?
答案 0 :(得分:0)
免责声明:我想最好的解决方案是明确使用context become
。我不建议您使用以下代码。
我想如果没有元编程(宏),这是不可能的。您必须使用命名参数的默认值创建方法。
你总是可以像这样手动创建这样的方法:
def update(filed1: Int = state.field1, field2: String = state.field2) =
context become foo(StateCaseClass(filed1, filed2))
...
update(field1 = 0)
...
update(field2 = "str")
但我想这不是你想要的。
获得没有元编程的方法的唯一方法是......使用方法copy
本身。方法copy
调用构造函数,您可以在构造函数中调用become
。
以下代码有效,但我强烈不建议您使用它!这是一个密码代码,它会让所有其他开发人员感到困惑。
import akka.actor._
trait ReceiveHelper extends PartialFunction[Any, Unit] {
def receive: PartialFunction[Any, Unit]
override def apply(v: Any) = receive(v)
override def isDefinedAt(v: Any) = receive isDefinedAt v
}
sealed trait TestActorMessage
case object Get extends TestActorMessage
case class SetInt(i: Int) extends TestActorMessage
case class SetString(s: String) extends TestActorMessage
class TestActor extends Actor {
case class Behaviour(intField: Int, strField: String) extends ReceiveHelper {
context become this
val receive: Receive = {
case Get => sender ! (intField -> strField)
case SetInt(i) => copy(intField = i)
case SetString(s) => copy(strField = s)
}
}
def receive = Behaviour(0, "init")
}
用法:
val system = ActorSystem("testSystem")
val testActor = system.actorOf(Props[TestActor], "testActor")
import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
implicit val timeout = Timeout(5 seconds)
testActor ? Get foreach println
// (0,init)
testActor ! SetInt(666)
testActor ? Get foreach println
// (666,init)
testActor ! SetString("next")
testActor ? Get foreach println
// (666,next)