Scala传递函数args到case类复制构造函数?

时间:2014-01-28 18:17:26

标签: scala akka

我有一些(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类复制构造函数并干掉最后一位?

1 个答案:

答案 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)