我有以下情况:
在初始化(实际上是第一次接收)套接字时,我想检查握手(TLS)中的某些内容,这必须仅在连接初始化时检查,而不是在每次进一步接收时检查。
目前我有一个奇怪的地方:
// this is happening outer scope
var somethingThatGetsComputedinInit = 0
def receive {
if (init) {
somethingThatGetsComputedinInit = doinitstuff(StuffIOnlyGetInitially)
init = false
}
}
虽然它会起作用,但这种气味非常危险。什么是纯粹的功能解决方案?
答案 0 :(得分:10)
在这种情况下,您希望在scala中使用lazy val
修饰符。这在Twitter's Effective Scala中有所建议。请考虑对您问题中的示例进行以下编辑。
class Foo {
def doinitstuff() : Int = {
println("I'm only going to be called once")
42
}
lazy val somethingThatGetsComputedinInit = doinitstuff()
def receive {
println(somethingThatGetsComputedinInit)
}
}
并且Foo调用多次接收实例的客户端将输出以下内容:
val foo = new Foo //> foo : worksheet.Foo = worksheet.Foo@5853c95f
foo.receive //> I'm only going to be called once
//| 42
foo.receive //> 42
foo.receive //> 42
答案 1 :(得分:4)
在您的具体示例中,由于您正在使用actor,因此您实际上可以使用"context.become
and context.unbecome
"替换其实现来建模状态机。在此基础上有一个抽象层Akka FSM,它为完成此类事物提供了更好的语法。
部分取消Akka FSM docs:
的示例sealed trait State
case object Initializing extends State
case object Initialized extends State
class Socket extends Actor with FSM[State, Option[Client]] {
startWith(Initializing, None)
when(Initializing) {
case Event(msg: Connect, _) => createClient(msg).fold(stay) {
client =>
//Do more stuff
goto(Initialized) using Some(client)
}
}
when(Initialized) {
case Event(msg: Receive, data@Some(client)) =>
//Do more stuff using client
stay using data
}
initialize()
}
答案 2 :(得分:1)
很棒的问题。
你一定要阅读状态模式。
有an example,摘自Eric Gamma Desing模式书*,与您一样,使用TCP连接。它不是函数式编程,但可以作为指导。
*设计模式的参考指南,hoverer我不推荐这本书,而是强烈鼓励你阅读Head First:设计模式,它具有更强大的教学工具,可以邀请你参与设计原则,更为重要比模式(和范例)。
希望它有所帮助!
答案 3 :(得分:0)
您还可以考虑将var与函数回调一起使用,并将var更新为在第一次之后不执行任何操作:
var firstTimeInit = StuffIOnlyGetInitially => doinitstuff(StuffIOnlyGetInitially)
// this is happening outer scope
var somethingThatGetsComputedinInit = 0
def receive {
somethingThatGetsComputedinInit = firstTimeInit(StuffIOnlyGetInitially)
firstTimeInit = StuffIOnlyGetInitially => ()
}
答案 4 :(得分:-1)
听起来像Scala“lazy val”的好用例。
lazy val somethingThatGetsComputedinInit = doinitstuff()
您可以保证val在首次使用时仅初始化一次。我不知道你的代码在哪里,如果它是正确的位置,但如果没有,你可以只参考“接收”里面的val来强制初始化。