在 scala 定义期间自引用一个 val
Self referencing a val during definition in scala
这是我在 scala 中发现的东西,它有效,但我不明白为什么,谁能解释为什么它有效?
基本上我可以在定义 val 时使用对它的引用(因为我的另一个 objects/actors 将它作为参数接收)
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 的具体情况,本月初的 post 中给出了非常好的解释:
请注意,在这种特定情况下,尽管代码可以编译,但它不会正确运行,因为正如对其他答案的评论中所建议的那样,传递给其他参与者的 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()
}
这会产生以下结果(重复,因为监管者策略会尝试重启 actor):
[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.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)
这是我在 scala 中发现的东西,它有效,但我不明白为什么,谁能解释为什么它有效?
基本上我可以在定义 val 时使用对它的引用(因为我的另一个 objects/actors 将它作为参数接收)
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 的具体情况,本月初的 post 中给出了非常好的解释:
请注意,在这种特定情况下,尽管代码可以编译,但它不会正确运行,因为正如对其他答案的评论中所建议的那样,传递给其他参与者的 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()
}
这会产生以下结果(重复,因为监管者策略会尝试重启 actor):
[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.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)