Не обнуляемый (по умолчанию)
В настоящее время эксперимент по ненулевому (по умолчанию) можно найти по адресу nullsafety.dartpad.dev .
Имейте в виду, что вы можете прочитать полную спецификацию здесь и полную дорожную карту здесь .
Что означает ненулевое значение по умолчанию?
void main() {
String word;
print(word); // illegal
word = 'Hello, ';
print(word); // legal
}
Как вы можете видеть выше, переменная, которая по умолчанию не имеет значения NULL , означает, что любая объявленная переменная не может быть 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равно NULL, и в противном случае преобразует ее в ненулевое значение 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
}
Смотрите также эту статью о синтаксическом решении .
?..
Оператор каскадный теперь имеет новый нуль осведомленный оператор: ?...
Это приводит к тому, что следующие каскадные операции будут выполняться только в том случае, если получатель не равен NULL . Следовательно, ?..должен быть первый каскадный оператор в каскадной последовательности:
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сам не может быть создан.
Ничто, кроме Nevera, не 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Насколько мне известно, программисты не должны использовать их.
Neverможно использовать?