【问题标题】:Self referencing a val during definition in scala在scala中定义期间自引用val
【发布时间】:2016-03-02 22:56:54
【问题描述】:

这是我在 scala 中发现的,它有效,但我不知道为什么,谁能解释为什么有效?

基本上我可以在定义 val 时使用它的引用(因为我的其他对象/参与者将它作为参数)

val backbone: ActorRef = context.actorOf(
  F_BackBone.props(
    context.actorOf(F_PictureHandler.props(backbone)), 
    context.actorOf(F_UserHandler.props(backbone)), 
    context.actorOf(F_PageProfileHandler.props(backbone))
  )
)

如果我没有明确定义类型,我会得到一个编译器错误,这是有道理的。

【问题讨论】:

    标签: scala recursion functional-programming akka


    【解决方案1】:

    请注意,在这种特定情况下,尽管代码可以编译,但它不会正确运行,因为正如 cmets 在另一个答案中所建议的那样,传递给其他参与者的 backbone 的值是“null”。

    这个例子证明了这一点:

    import akka.actor.{Props, Actor, ActorRef, ActorSystem}
    
    class SenderReceiver(sendTo:ActorRef) extends Actor{
    
      override def preStart(): Unit = {
        self ! "Start"
      }
    
      def receive = {
        case "Start" => sendTo ! "Hello"
        case "Hello" => println("Received Hello")
      }
    }
    
    object SenderReceiver {
      def props(sendTo:ActorRef):Props = Props(new SenderReceiver(sendTo))
    }
    
    object Example extends App {
    
      val system = ActorSystem()
    
      val actor: ActorRef = system.actorOf(SenderReceiver.props(actor))
      system.awaitTermination()
    }
    

    这会产生以下结果(重复,因为主管策略会尝试重新启动参与者):

    [info] [ERROR] [12/01/2015 09:47:04.543] [default-akka.actor.default-dispatcher-9] [akka://default/user/$a] null
    [info] java.lang.NullPointerException
    [info]  at SenderReceiver$$anonfun$receive$1.applyOrElse(example.scala:10)
    [info]  at akka.actor.Actor$class.aroundReceive(Actor.scala:467)
    [info]  at SenderReceiver.aroundReceive(example.scala:3)
    [info]  at akka.actor.ActorCell.receiveMessage(ActorCell.scala:516)
    [info]  at akka.actor.ActorCell.invoke(ActorCell.scala:487)
    [info]  at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:238)
    [info]  at akka.dispatch.Mailbox.run(Mailbox.scala:220)
    [info]  at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:397)
    [info]  at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
    [info]  at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
    [info]  at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
    [info]  at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
    

    【讨论】:

      【解决方案2】:

      在函数式编程语言中,递归定义是一个重要的概念。以定义阶乘的经典示例为例。

      对于 Scala 的具体情况,本月早些时候的一篇文章中给出了非常好的解释: A variable used in its own definition?

      【讨论】:

      • 但这不是递归定义,它是在构造之前传递的引用
      • 尽管如此,我想说 Archeg 在另一个线程中所做的评论适用:“[...] variable a is created when you type val a: Int, [...]” .您有一个用户定义的类型,而不是 Int,所以 backbone 将在右侧初始化为 null
      • @ChristianHirsch 我也有同样的理解。这意味着,context.actorOf(F_UserHandler.props(backbone)) 将接收 backbone 作为 null,除非它被延迟评估(按名称调用、延迟验证等)。也许通过null 在这里引入了一个潜在的错误。
      猜你喜欢
      • 2013-11-05
      • 2013-12-23
      • 1970-01-01
      • 2014-09-14
      • 1970-01-01
      • 2020-10-22
      • 1970-01-01
      • 1970-01-01
      • 2011-01-17
      相关资源
      最近更新 更多