2015-11-29 22 views
5

To jest coś, co dowiedziałem się w scala i działa i nie mogę zrozumieć dlaczego, czy ktoś może wyjaśnić, dlaczego to działa?Samo odwołanie się do val podczas definicji w scala

Zasadniczo można użyć odniesienia do val a ja nadal zdefiniowaniem (bo moje inne obiekty/Aktorzy wziąć go jako parametr)

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

będę się błąd kompilatora, jeśli don” t jawnie zdefiniować typ, który ma sens.

Odpowiedz

1

Należy zauważyć, że w tym konkretnym przypadku, chociaż kod kompiluje, nie będzie zachowywać się poprawnie, ponieważ, jak sugerowane w komentarzach do drugiej odpowiedzi, wartość backbone przekazana innym aktorom to "null".

Ten przykład pokazuje to:

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

Daje to następujące (wielokrotnie, ponieważ strategia przełożony próbuje ponownie uruchomić aktor):

[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) 
1

W językach programowania funkcjonalnego definicje rekurencyjne są ważną koncepcją. Pomyśl na przykład o klasycznym przykładzie definiowania silni.

Dla konkretnego przypadku Scala, bardzo miły wyjaśnienie podano w poście wcześniej w tym miesiącu: A variable used in its own definition?

+1

Ale to nie jest rekurencyjna definicja, to referencja przeszła zanim została skonstruowana –

+1

Niemniej jednak powiedziałbym, że komentarz dodany w drugim wątku przez Archeg dotyczy: "[...] zmienna' a' jest tworzona po wpisaniu 'val a: Int', [.. .] ". Masz typ zdefiniowany przez użytkownika, a nie Int, więc 'kręgosłup' zostanie zainicjowany na' null' po prawej stronie –

+0

@ ChrześcijanieHirsch Mam takie samo zrozumienie. Co oznacza, że ​​'context.actorOf (F_UserHandler.props (backbone))' otrzyma 'szkielet' jako 'null', chyba że jest on oceniany leniwie (call-by-name, leniwy val itd.). Być może potencjalny błąd jest tutaj wprowadzany przez 'null'. – tuxdna