Scala - Initialisierungsreihenfolge von Vals

8

Ich habe dieses Stück Code, das Eigenschaften aus einer Datei lädt:

%Vor%

Das scheint gut zu funktionieren.

Ich habe versucht, die Initialisierung von properties in ein anderes val, loadedProperties , wie folgt zu verschieben:

%Vor%

}

Aber es funktioniert nicht! ( properties ist null in properties.get("forum_id") ).

Warum sollte das sein? Wird loadedProps nicht ausgewertet, wenn auf properties verwiesen wird?

Zweitens, ist dies eine gute Möglichkeit, Variablen zu initialisieren, die eine nicht-triviale Verarbeitung erfordern? In Java würde ich sie final -Felder deklarieren und die initialisierungsbezogenen Operationen im Konstruktor ausführen.

Gibt es in Scala ein Muster für dieses Szenario?

Danke!

    
teo 28.01.2013, 17:50
quelle

3 Antworten

18

Vals werden in der Reihenfolge initialisiert, in der sie deklariert werden (naja, genau, nicht faul vals), also wird properties vor loadedProps initialisiert. Oder mit anderen Worten, loadedProps ist immer noch null , wenn properties initialisiert wird. Die einfachste Lösung ist hier loadedProps vor properties zu definieren:

%Vor%

Sie könnten auch loadedProps lazy machen, was bedeutet, dass es bei seinem ersten Zugriff initialisiert wird:

%Vor%

Die Verwendung von lazy val hat den Vorteil, dass Ihr Code robuster für das Refactoring ist, da nur eine Änderung der Deklarationsreihenfolge Ihrer Werte Ihren Code nicht unterbricht.

Auch in diesem speziellen Fall können Sie loadedProps in ein def (wie von @NIA vorgeschlagen) verwandeln, da es sowieso nur einmal verwendet wird.

    
Régis Jean-Gilles 28.01.2013, 18:42
quelle
4

Ich denke, hier loadedProps kann einfach in eine Funktion umgewandelt werden, indem einfach val durch def ersetzt wird:

%Vor%

In diesem Fall sind Sie sicher, dass es beim Aufruf aufgerufen wird.

Aber nicht sicher ist es ein Muster für diesen Fall.

    
NIA 28.01.2013 17:54
quelle
0

Nur ein Zusatz mit ein wenig mehr Erklärung:

Ihr properties -Feld wird hier früher initialisiert als das loadedProps -Feld. null ist der Wert eines Feldes vor der Initialisierung - darum bekommst du es. In def ist es nur ein Methodenaufruf, anstatt auf ein Feld zuzugreifen, also ist alles in Ordnung (da der Methodencode mehrmals aufgerufen werden kann - hier keine Initialisierung). Siehe Ссылка . Sie können def oder lazy val verwenden, um es zu reparieren

Warum def ist so anders? Das liegt daran, dass def mehrmals aufgerufen werden kann, aber val - nur einmal (der erste und einzige Aufruf ist also die Initialisierung der Datei).

lazy val kann nur initialisiert werden, wenn Sie es aufrufen, also würde es auch helfen.

Ein anderes, einfacheres Beispiel für das, was vor sich geht:

%Vor%

Allgemein gesprochen, könnte scala theoretisch den Abhängigkeitsgraphen zwischen Feldern analysieren (welches Feld ein anderes Feld benötigt) und die Initialisierung von den letzten Knoten starten. Aber in der Praxis wird jedes Modul separat kompiliert und der Compiler kennt vielleicht nicht einmal diese Abhängigkeiten (es könnte sogar Java sein, das Scala aufruft, welches Java aufruft), also mache einfach sequentielle Initialisierung.

Aus diesem Grund konnte es nicht einmal einfache Schleifen entdecken:

%Vor%

Tatsächlich kann eine solche Schleife (innerhalb eines Moduls) theoretisch in einem separaten Build erkannt werden, aber es wird nicht viel helfen, da es ziemlich offensichtlich ist.

    
dk14 16.04.2015 12:27
quelle