2010-12-09 6 views
3

diese Situation gegeben:Kann ich "method-private" Felder in Scala definieren?

object ResourceManager { 

    private var inited = false 

    def init(config: Config) { 
    if (inited) 
     throw new IllegalStateException 
    // do initialization 
    inited = true 
    } 

} 

Gibt es eine Möglichkeit, die ich inited irgendwie „privaten() init“ machen könnte, so dass ich sicher sein, dass keine andere Methode in dieser Klasse jemals in der Lage sein zu setzen inited = false?

+0

Siehe auch http://StackOverflow.com/questions/1516087 – Debilski

Antwort

6

Aufgenommen von In Scala, how would you declare static data inside a function?. Kein Verfahren, sondern ein Funktionsobjekt verwenden:

val init = { // or lazy val 
    var inited = false 

    (config: Config) => { 
     if (inited) 
      throw new IllegalStateException 

     inited = true 
    } 
} 

Während der Initialisierung des äußeren Umfangs (im Fall von val) oder den ersten Zugang (lazy val), wird der Körper der Variablen ausgeführt. Daher wird inited auf false festgelegt. Der letzte Ausdruck ist eine anonyme Funktion, die dann init zugewiesen wird. Jeder weitere Zugriff auf init führt dann diese anonyme Funktion aus.

Beachten Sie, dass es sich nicht genau wie eine Methode verhält. I.e. es ist durchaus zulässig, es ohne Argumente zu nennen. Es wird sich dann wie eine Methode mit dem abschließenden Unterstrich method _ verhalten, was bedeutet, dass es nur die anonyme Funktion zurückgibt, ohne sich zu beschweren.

Wenn Sie aus irgendeinem Grund tatsächlich ein Methodenverhalten benötigen, können Sie es zu einem private val _init = ... machen und es aus dem öffentlichen def init(config: Config) = _init(config) aufrufen.

+0

Gute Antwort. Ich habe darüber nachgedacht, aber ich habe den Sprung von "def" zu "val" nicht gemacht, um es zum Laufen zu bringen. –

+0

Schön in der Tat! Vielen Dank! –

+0

Schön, wenn fast zu schlau. –

5

Das untenstehende zählt absolut als viel mehr Ärger, der es wert ist, aber erfüllt die Spezifikationen. Es gibt keinen Weg, um es anders zu machen

object ResourceManager { 

    private object foo { 
    var inited = false 
    def doInit(config:Config){ 
     if (inited) 
     throw new IllegalStateException 
     // do initialization 
     inited = true 
    } 
    } 


    def inner(config: Config) { 
     foo.doInit(config) 
    } 

} 
0

Es wäre einfacher, eine „Falltür“ Objekt zu erstellen, die nur von false auf true gehen kann:

object ResourceManager { 

    object inited { 
    private var done = false 

    def apply() = done 
    def set = done = true 
    } 

    def init(config: Int) { 

    if (inited()) 
     throw new IllegalStateException 
    // do initialization 
    inited.set 
    } 

} 
+0

Aber konnte nicht inited.set von einer anderen Methode aufgerufen werden? – Bruna

+0

Sie sagten: "Stellen Sie sicher, dass keine andere Methode' inited = false' setzen kann. " Es gibt keine Möglichkeit für * any * -Methode, sie in meinem Beispiel mit 'set' auf false zu setzen. –

0

Wenn alles, was Sie tun möchten, ist sicher machen dass init einmal, so etwas wie dies genannt:

lazy val inited = { 
    // do the initialization 
    true 
} 

def init = inited 

auf diese Weise die Initialisierung Code nur einmal ausgeführt werden soll, aber oft Sie init laufen, und 0.123.kann keinen anderen Wert erhalten, da es sich um eine val handelt. Der einzige Nachteil ist, dass, sobald inited für seinen Wert abgefragt wird, die Initialisierung ausgeführt wird ...

+0

Das Problem hier ist, dass er nicht will, dass gesetzt wird, aber sein Wert könnte vor der ordnungsgemäßen Inizialisierung überprüft werden. – Bruna