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:
}
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!
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:
Sie könnten auch loadedProps
lazy machen, was bedeutet, dass es bei seinem ersten Zugriff initialisiert wird:
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.
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.
Tags und Links scala constructor initialization immutability final