Wie erstelle ich private Variablen in Dart?

74

Ich möchte eine private Variable erstellen, kann dies aber nicht.

Hier ist mein 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');
  }
}

Wenn ich diesen Code ausführe, erhalte ich das folgende Ergebnis:

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

Außerdem erhalte ich beim Bearbeiten dieses Quellcodes keine Fehler oder Warnungen.

Wie kann ich eine private Variable in Dart erstellen?

Matt C.
quelle

Antworten:

130

Aus der Dart-Dokumentation:

Im Gegensatz zu Java verfügt Dart nicht über die Schlüsselwörter public, protected und private. Wenn ein Bezeichner mit einem Unterstrich beginnt _, ist er für seine Bibliothek privat.

Bibliotheken bieten nicht nur APIs, sondern sind auch eine Einheit zum Schutz der Privatsphäre: Bezeichner, die mit einem Unterstrich beginnen, _sind nur in der Bibliothek sichtbar.

Ein paar Worte zu Bibliotheken:

Jede Dart-App ist eine Bibliothek, auch wenn sie keine Bibliotheksanweisung verwendet. Mit den Import- und Bibliotheksanweisungen können Sie eine modulare und gemeinsam nutzbare Codebasis erstellen.

Möglicherweise haben Sie von der partDirektive gehört, mit der Sie eine Bibliothek in mehrere Dart-Dateien aufteilen können.

Mezoni
quelle
2
Was macht eine Bibliothek aus?
CodeGrue
F: Was definiert eine Bibliothek? A: Der Antwort wurde ein kleiner Zusatz hinzugefügt.
Mezoni
52

Datenschutz in Dart besteht eher in der Bibliothek als auf Klassenebene.

Wenn Sie Klasse A in eine separate Bibliotheksdatei einfügen (z. B. other.dart), z.

library other;

class A {
  int _private = 0;

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

und importieren Sie es dann in Ihre Haupt-App, z.

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
  }
}

Sie erhalten die erwartete Ausgabe:

String value: Hello
int value: 0
int value: 5
String value: Hello
Chris Buckett
quelle
3
Dies sollte die akzeptierte Antwort sein, da die ursprüngliche Frage bereits den Unterstrich verwendete, um die Kennung als privat zu kennzeichnen.
Nick Korostelev
Vielen Dank für diese Zeile "Datenschutz in Dart existiert in der Bibliothek und nicht auf Klassenebene"
Shahriar Nasim Nafi
8

Die Top-Antwort ist ab sofort definitiv richtig.

Ich werde versuchen, in dieser Antwort näher darauf einzugehen.

Ich werde die Frage beantworten, aber damit beginnen: So soll Dart einfach nicht geschrieben werden, auch weil bibliotheksprivate Mitglieder es einfacher machen, Operatoren wie zu definieren ==. (Private Variablen eines zweiten Objekts konnten für den Vergleich nicht angezeigt werden.)

Nachdem wir das aus dem Weg geräumt haben, zeige ich Ihnen zunächst, wie es gemacht werden soll (bibliotheksprivat statt klassenprivat), und zeige Ihnen dann, wie Sie eine Variable klassenprivat machen, wenn das willst du immer noch wirklich. Auf geht's.

Wenn eine Klasse keine geschäftlichen Variablen in einer anderen Klasse sieht, fragen Sie sich möglicherweise, ob sie wirklich zur selben Bibliothek gehören:

    //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
    }

Das sollte gut sein. Wenn Sie jedoch wirklich private Klassendaten möchten:

Obwohl Sie technisch private Variablen zu erstellen ist nicht erlaubt, Sie könnten es emulieren die folgende Verschlusstechnik.

(Sie sollten jedoch sorgfältig überlegen, ob Sie es wirklich brauchen und ob es einen besseren, dartartigeren Weg gibt, um das zu tun, was Sie erreichen wollen!)

    //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.
    }

Also ja. Seien Sie vorsichtig und versuchen Sie, die Best Practices der Sprache zu befolgen. Es sollte Ihnen gut gehen.

BEARBEITEN

Anscheinend gibt es eine neue typedef-Syntax, die für Dart 2 bevorzugt wird. Wenn Sie Dart 2 verwenden, sollten Sie diese verwenden. Oder, noch besser, verwenden Sie Inline-Funktionstypen.

Wenn Sie die zweite verwenden, ist sie weniger ausführlich, aber die anderen Probleme bleiben bestehen.

AaronF
quelle
Der Abschnitt Bibliotheken in Effective Dart ist ebenfalls eine gute Ressource.
AaronF
Bekommt das in Ihrem ersten Snippet nicht _valimplizit einen Getter und einen Setter?
Regen
Offtopic: MyClass.fromVal(int val) : _val = val;- Ist dies der Weg, um statische Methoden zu erstellen ?
Sonic
2

In dart wird _ vor dem Variablennamen verwendet, um ihn als privat zu deklarieren. Im Gegensatz zu anderen Programmiersprachen bedeutet privat nicht, dass es nur für die Klasse verfügbar ist, in der es sich befindet. Privat bedeutet, dass es in der Datei, in der es sich befindet, zugänglich ist und für andere Dateien nicht zugänglich ist.

Bensal
quelle