簡體   English   中英

Scala將函數args傳遞給case類復制構造函數?

[英]Scala pass function args through to case class copy constructor?

我有一些(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類副本構造函數並耗盡最后一點?

免責聲明 :我猜最好的解決方案是使用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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM