web-dev-qa-db-fra.com

Comment créer des variables privées dans Dart?

Je veux créer une variable privée mais je ne peux pas.

Voici mon code:

void main() {
  var b = new B();
  b.testB();    
}

class A {
  int _private = 0;

  testA() {
    print('int value: $_private');
    _private = 5;
  }
}

class B extends A {
  String _private;

  testB() {
    _private = 'Hello';
    print('String value: $_private');
    testA();
    print('String value: $_private');
  }
}

Lorsque j'exécute ce code, j'obtiens le résultat suivant:

String value: Hello
int value: Hello
Breaking on exception: type 'int' is not a subtype of type 'String' of 'value'.

De plus, je ne reçois aucune erreur ni aucun avertissement lors de la modification de ce code source.

Comment créer une variable privée dans Dart?

39
user2553310

De la documentation Dart:

Contrairement à Java, Dart n'a pas les mots clés public, protected et private. Si un identifiant commence par un trait de soulignement _, il est privé de sa bibliothèque.

Les bibliothèques fournissent non seulement des API, mais constituent une unité de confidentialité: les identifiants qui commencent par un trait de soulignement _ ne sont visibles qu'à l'intérieur de la bibliothèque.

70
mezoni

La confidentialité dans Dart existe à la bibliothèque, plutôt qu'au niveau de la classe.

Si vous deviez mettre la classe A dans un fichier de bibliothèque séparé (par exemple, other.Dart), tel que:

library other;

class A {
  int _private = 0;

  testA() {
    print('int value: $_private');  // 0
    _private = 5;
    print('int value: $_private'); // 5
  }
}

puis importez-le dans votre application principale, par exemple:

import 'other.Dart';

void main() {
  var b = new B();
  b.testB();    
}


class B extends A {
  String _private;

  testB() {
    _private = 'Hello';
    print('String value: $_private'); // Hello
    testA();
    print('String value: $_private'); // Hello
  }
}

Vous obtenez la sortie attendue:

String value: Hello
int value: 0
int value: 5
String value: Hello
23
Chris Buckett

La meilleure réponse à ce jour est certainement correcte.

J'essaierai d'aller plus en détail dans cette réponse.

Je vais répondre à la question, mais commencez par ceci: ce n'est tout simplement pas comme cela que Dart est censé être écrit, en partie parce que les membres de bibliothèque privés facilitent la définition d'opérateurs comme ==. (Les variables privées d'un deuxième objet n'ont pas pu être vues pour la comparaison.)

Maintenant que nous avons éliminé cela, je vais commencer par vous montrer comment cela doit être fait (bibliothèque privée au lieu de classe privée), puis vous montrer comment rendre une variable classe privée si vous le voulez toujours. Et c'est parti.

Si une classe n'a rien à voir avec les variables d'une autre classe, vous pouvez vous demander si elles appartiennent vraiment à la même bibliothèque:

    //This should be in a separate library from main() for the reason stated in the main method below.

    class MyClass {
      //Library private variable
      int _val = 0;

      int get val => _val;
      set val(int v) => _val = (v < 0) ? _val : v;

      MyClass.fromVal(int val) : _val = val;
    }

    void main() {
      MyClass mc = MyClass.fromVal(1);
      mc.val = -1;
      print(mc.val); //1

      //main() MUST BE IN A SEPARATE LIBRARY TO 
      //PREVENT MODIFYING THE BACKING FIELDS LIKE:
      mc._val = 6;
      print(mc.val); //6
    }

Ça devrait être bien. Cependant, si vous voulez vraiment des données de classe privées:

Bien que vous ne soyez techniquement pas autorisé à créer des variables privées, vous pourriez l'émuler en utilisant la technique de fermeture suivante.

(CEPENDANT, vous devriez soigneusement examiner si vous en avez vraiment besoin et s'il existe une meilleure façon, plus semblable à Dart, de faire ce que vous essayez d'accomplir!)

    //A "workaround" that you should THINK TWICE before using because:
    //1. The syntax is verbose.
    //2. Both closure variables and any methods needing to access
    //   the closure variables must be defined inside a base constructor.
    //3. Those methods require typedefs to ensure correct signatures.

    typedef int IntGetter();
    typedef void IntSetter(int value);

    class MyClass {
      IntGetter getVal;
      IntSetter setVal;

      MyClass.base() {
        //Closure variable
        int _val = 0;

        //Methods defined within constructor closure
        getVal = ()=>_val;
        setVal = (int v) => _val = (v < 0) ? _val : v;
      }

      factory MyClass.fromVal(int val) {
        MyClass result = MyClass.base();
        result.setVal(val);
        return result;
      }
    }

    void main() {
      MyClass mc = MyClass.fromVal(1);
      mc.setVal(-1); //Fails
      print(mc.getVal());

      //On the upside, you can't access _val
      //mc._val = 6; //Doesn't compile.
    }

Donc voilà. Soyez juste prudent et essayez de suivre les meilleures pratiques de la langue et ça devrait aller.

MODIFIER

Apparemment, il existe une nouvelle syntaxe typedef préférée pour Dart 2. Si vous utilisez Dart 2, vous devriez l'utiliser. Ou, encore mieux, utilisez des types de fonctions en ligne.

Si vous utilisez le second, il sera moins détaillé, mais les autres problèmes demeurent.

5
AaronF