Що таке Nullability у Dart (Не зазначається за замовчуванням)?


27

Я чув про нову функцію мови безпеки Dart, яка в даний час є "експериментом, який не зводиться до нуля ". Передбачається, що за замовчуванням введено нерегульоване .

Специфікацію функцій можна знайти тут, а мову GitHub видати тут .

Як це працює і де його можна спробувати?

Відповіді:


49

Не нульовий (за замовчуванням)

Ненульовий (за замовчуванням) експеримент наразі можна знайти на сайті nullsafety.dartpad.dev .
Майте на увазі, що ви можете прочитати повну специфікацію тут, а повну дорожню карту тут .


Що означає ненульове значення за замовчуванням?

void main() {
  String word;
  print(word); // illegal

  word = 'Hello, ';
  print(word); // legal
}

Як ви бачите вище, зміна, яка за замовчуванням є ненульовою , означає, що кожна змінна, яка оголошується зазвичай, не може бути null. Отже, будь-яка операція, що отримує доступ до змінної до її призначення, є незаконною.
Крім того, nullтакож заборонено присвоєння змінної, що не змінюється:

void main() {
  String word;

  word = null; // forbidden
  world = 'World!'; // allowed
}

Як мені це допомагає?

Якщо змінна не є нульовою , ви можете бути впевнені, що вона ніколи не буває null. Через це вам ніколи не потрібно це попередньо перевіряти.

int number = 4;

void main() {
  if (number == null) return; // redundant

  int sum = number + 2; // allowed because number is also non-nullable
}

Пам'ятайте

Поля екземплярів у класах повинні бути ініціалізовані, якщо вони не зведені до нуля:

class Foo {
  String word; // forbidden

  String sentence = 'Hello, World!'; // allowed
}

Див. lateНижче, щоб змінити цю поведінку.

Зменшувані типи ( ?)

Ви можете використовувати зведені типи , додавши знак питання ?до змінної типу:

class Foo {
  String word; // forbidden

  String? sentence; // allowed
}

Обнуляє змінна не повинна бути инициализирована , перш ніж він може бути використаний. Він ініціалізується nullза замовчуванням:

void main() {
  String? word;

  print(word); // prints null
}

!

Додавання !до будь-якої змінної eпризведе до помилки виконання, якщо вона eє нульовою, і іншим чином перетворить її в ненульове значення v.

void main() {
  int? e = 5;
  int v = e!; // v is non-nullable; would throw an error if e were null

  String? word;
  print(word!); // throws runtime error if word is null

  print(null!); // throws runtime error
}

late

Ключове слово lateможна використовувати для позначення змінних, які будуть ініціалізовані пізніше , тобто не тоді, коли вони оголошені, а коли вони отримують доступ. Це також означає, що ми можемо мати ненульові поля екземпляра , які ініціалізуються пізніше:

class ExampleState extends State {
  late String word; // non-nullable

  @override
  void initState() {
    super.initState();

    // print(word) here would throw a runtime error
    word = 'Hello';
  }
}

Доступ wordдо його ініціалізації призведе до помилки виконання.

late final

Кінцеві змінні тепер також можуть бути позначені пізно:

late final int x = heavyComputation();

Тут heavyComputationбуде викликано лише один раз, коли xбуде доступ. Крім того, ви також можете оголосити late finalбез ініціалізатора, що є тим самим, що має лише lateзмінну, але це може бути призначено лише один раз.

late final int x;
// w/e
x = 5; // allowed
x = 6; // forbidden

Зауважте, що всі змінні верхнього рівня або статичні з ініціалізатором тепер будуть оцінені late, незалежно від того, чи є вони final.

required

Раніше примітка ( @required), тепер вбудована як модифікатор. Це дозволяє позначити будь-який названий параметр (для функцій або класів) як required, що робить їх ненульовими:

void allowed({required String word}) => null;

Це також означає, що якщо параметр повинен бути ненульовим , його потрібно позначити як requiredабо мати значення за замовчуванням:

void allowed({String word = 'World'}) => null;

void forbidden({int x}) // compile-time error because x can be null (unassigned)
    =>
    null;

Будь-який інший названий параметр повинен бути нульовим :

void baz({int? x}) => null;

?[]

Для ?[]оператора індексу додано оператор, що знає нуль []:

void main() {
  List<int>? list = [1, 2, 3];

  int? x = list?[0]; // 1
}

Дивіться також цю статтю про рішення синтаксису .

?..

Оператор каскадний тепер має новий нуль обізнаний оператор: ?...

Це призводить до виконання наступних операцій каскаду, лише якщо одержувач не є нульовим . Таким чином, ?..повинен бути першим оператором каскаду в послідовності каскаду:

void main() {
  Path? path;

  // Will not do anything if path is null.
  path
    ?..moveTo(3, 4)
    ..lineTo(4, 3);

  // This is a noop.
  (null as List)
    ?..add(4)
    ..add(2)
    ..add(0);
}

Never

Щоб уникнути плутанини: розробникам це не варто турбуватися. Хочу згадати це заради повноти.

Neverбуде таким типом, як раніше існуючий Null( неnull ) визначений в dart:core. Обидва ці класи не можуть бути розширені, впроваджені або змішані, тому вони не призначені для використання.

По суті, Neverозначає, що жоден тип не дозволений і Neverйого неможливо створити.
Нічого , крім Neverпротягом List<Never>задовольняє загальний тип обмеження списку, що означає , що він повинен бути порожніми . List<Null>Однак може містити null:

// Only valid state: []
final neverList = <Never>[
  // Any value but Never here will be an error.
  5, // error
  null, // error

  Never, // not a value (compile-time error)
];

// Can contain null: [null]
final nullList = <Null>[
  // Any value but Null will be an error.
  5, // error
  null, // allowed

  Never, // not a value (compile-time error)
  Null, // not a value (compile-time error)
];

Приклад: компілятор буде робити висновок List<Never>про порожнє const List<T> .
Neverне передбачається використовувати програмістами, наскільки я переживаю.


5
Чи можете ви дати кілька сценаріїв, де Neverїх можна використовувати?
Рамзес Алдама

2
Ми фактично вирішили використовувати "? []" Для оператора індексів, що знає нуль, а не "?. []". Останнє граматично трохи складніше, але це те, чого хочуть користувачі.
чудовий

@RamsesAldama Я щось додав. Специфікація, яку я пов'язував, згадує більше.
creativecreatorormaybenot

@mulous Спеціалізація та експеримент тоді ще застаріли; дякую за вказівку.
creativecreatorormaybenot

1
Слід зазначити, що late finalзмінну члена або екземпляра перевіряє лише під час виконання. Неможливо перевірити це на час розробки чи час компіляції через проблему зупинки. Таким чином, ви не отримаєте допомогу IDE з цим.
Грем
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.