4

我有以下情况:

在初始化(实际上是第一次接收)套接字时,我想检查握手(TLS)中的某些内容,这只能在连接初始化时检查,而不是在每次进一步接收时检查。

目前我有一个奇怪的:

   // this is happening outer scope
   var somethingThatGetsComputedinInit = 0

   def receive {
      if (init) {
        somethingThatGetsComputedinInit = doinitstuff(StuffIOnlyGetInitially)
        init = false
      }
    }

虽然它会起作用,但这闻起来是如此迫切和难看。什么是纯粹的功能解决方案?

4

5 回答 5

10

这是您想lazy val在 scala 中使用修饰符的情况。这是在Twitter 的 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 实例的客户端多次调用 receive 将输出以下内容:

 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
于 2013-10-19T19:23:44.447 回答
4

在您的具体示例中,由于您使用的是演员,因此您实际上可以换出其实现以使用"context.becomecontext.unbecome"对状态机进行建模。在此之上有一个抽象层Akka FSM ,它提供了一种更好的语法来完成这种类型的事情。

部分摘自Akka FSM 文档的示例:

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()

}
于 2013-10-19T20:32:29.693 回答
1

很好的问题。

您绝对应该阅读state pattern

从 Eric Gamma Desing patterns book*中提取了一个示例,该示例与您一样适用于 TCP 连接。它不是函数式编程,但可以为您提供指导。

*设计模式的参考指南,hoverer 我不推荐这本书,相反我强烈建议你阅读 Head First :设计模式,它具有更强大的教学工具,可以邀请你使用设计原则做事,远比模式重要(和范式)。

希望能帮助到你!

于 2013-10-19T18:58:57.803 回答
0

听起来像是 Scala“lazy val”的好用例。

lazy val somethingThatGetsComputedinInit = doinitstuff()

您可以保证 val 在第一次使用时只被初始化一次。我不知道你的代码在哪里,如果它是正确的地方,但如果不是,你可以参考“receive”中的 val 来强制初始化。

于 2013-10-19T19:36:19.223 回答
0

您还可以考虑将 var 与函数回调一起使用,并在第一次之后更新 var 以不执行任何操作:

   var firstTimeInit = StuffIOnlyGetInitially => doinitstuff(StuffIOnlyGetInitially)

   // this is happening outer scope
   var somethingThatGetsComputedinInit = 0

   def receive {
        somethingThatGetsComputedinInit = firstTimeInit(StuffIOnlyGetInitially)
        firstTimeInit = StuffIOnlyGetInitially => ()
    }
于 2016-09-25T15:36:19.500 回答