Как создать приватные переменные в Dart?

Я хочу создать личную переменную, но не могу.

Вот мой код:

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

Когда я запускаю этот код, я получаю следующий результат:

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

Также я не получаю никаких ошибок или предупреждений при редактировании этого исходного кода.

Как я могу создать личную переменную в Dart?

Ответ 1

Из документации Dart:

В отличие от Java, Dart не имеет общедоступных, защищенных и закрытых ключевых слов. Если идентификатор начинается с символа подчеркивания _, его частный доступ к его библиотеке.

Библиотеки не только предоставляют API, но и являются частью конфиденциальности: идентификаторы, начинающиеся с символа подчеркивания _, видны только внутри библиотеки.

Ответ 2

Конфиденциальность в Дарте существует в библиотеке, а не на уровне класса.

Если вы должны поместить класс A в отдельный файл библиотеки (например, other.dart), например:

library other;

class A {
  int _private = 0;

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

а затем импортируйте его в основное приложение, например:

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

Вы получаете ожидаемый результат:

String value: Hello
int value: 0
int value: 5
String value: Hello

Ответ 3

Главный ответ на данный момент, безусловно, правильный.

Я постараюсь углубиться в этот ответ.

Я отвечу на вопрос, но приведу следующее: это не совсем то, как Dart предназначен для написания, отчасти потому, что закрытые члены библиотеки упрощают определение таких операторов, как ==. (Частные переменные второго объекта нельзя было увидеть для сравнения.)

Теперь, когда мы это получили, я начну с того, что покажу вам, как это должно быть сделано (библиотека-приват вместо класса-приват), а затем покажу, как сделать переменную класса приватной, если Вы все еще действительно хотите этого. Вот так.

Если у одного класса нет бизнес-переменных, видимых в другом классе, вы можете спросить себя, действительно ли они принадлежат одной и той же библиотеке:

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

Так что да. Просто будьте осторожны и старайтесь следовать языковым рекомендациям, и у вас все будет хорошо.

РЕДАКТИРОВАТЬ

Очевидно, есть новый синтаксис typedef, который предпочтителен для Dart 2. Если вы используете Dart 2, вы должны использовать его. Или, что еще лучше, используйте встроенные типы функций.

Если вы используете второе, оно будет менее многословным, но другие проблемы останутся.