2010-12-09 2 views
3

Face à cette situation:Puis-je définir des champs "method-private" dans Scala?

object ResourceManager { 

    private var inited = false 

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

} 

Est-il possible que je puisse faire inited en quelque sorte « privé (init) », de sorte que je peux être sûr qu'aucune autre méthode dans cette classe ne sera jamais en mesure de définir inited = false?

+0

Voir aussi http://stackoverflow.com/questions/1516087 – Debilski

Répondre

6

Tiré de In Scala, how would you declare static data inside a function?. Ne pas utiliser une méthode, mais un objet de fonction:

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

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

     inited = true 
    } 
} 

Lors de l'initialisation du champ extérieur (en cas de val) ou au premier accès (lazy val), le corps de la variable est exécutée. Par conséquent, inited est défini sur false. La dernière expression est une fonction anonyme qui est ensuite affectée à init. Chaque accès supplémentaire à init exécutera alors cette fonction anonyme.

Notez qu'il ne se comporte pas exactement comme une méthode. C'est à dire. il est parfaitement valable de l'appeler sans arguments. Il se comportera alors comme une méthode avec un trait de soulignement final method _, ce qui signifie qu'il retournera simplement la fonction anonyme sans se plaindre.

Si pour une raison ou pour une autre, vous avez réellement besoin d'un comportement de méthode, vous pouvez en faire un private val _init = ... et l'appeler du public def init(config: Config) = _init(config).

+0

Bonne réponse. J'y pensais, mais je ne faisais pas le saut de 'def' à' val' pour que ça marche. –

+0

Nice en effet! Merci! –

+0

Jolie, si presque trop intelligent. –

5

Le ci-dessous compte d'autant plus de problèmes que cela vaut la peine, mais satisfait les spécifications. Il n'y a aucun moyen de le faire autrement

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

Il serait plus facile de créer un « trapdoor » objet qui ne peut aller de faux vrai:

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

Mais inited.set ne peut-il pas être appelé par une autre méthode? – Bruna

+0

Vous avez dit "assurez-vous qu'aucune autre méthode ne peut définir' inited = false' ". Il n'y a aucun moyen pour * toute * méthode de le définir à false avec 'set' dans mon exemple. –

0

Si tout ce que vous voulez faire est de vous assurer que init est appelé une fois, faire quelque chose comme ceci:

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

def init = inited 

cette façon, le code d'initialisation ne fonctionnera une fois, mais plusieurs fois que vous exécutez init et inited ne peut pas obtenir une autre valeur car il s'agit d'un val. Le seul inconvénient est que dès que inited est interrogé pour sa valeur l'initialisation se déroulera ...

+0

Le problème ici est qu'il n'a pas été créé pour être mis en place, mais sa valeur pourrait être vérifiée avant l'inicialisation correcte. – Bruna

Questions connexes