Что такое нулевая безопасность в Dart?
Я слышал о новой функции языка безопасности с нулевым значением Dart (NNBD), которая в настоящее время является " экспериментом, не допускающим значения NULL ". По умолчанию предполагается ввести значение, не допускающее значения NULL.
Спецификацию функции можно найти здесь, а вопрос о языке GitHub здесь.
Как это работает и где я могу это попробовать?
2 ответа
1. Безопасность с нулевым значением / не допускающее значение NULL (по умолчанию)
Нулевую безопасность / не допускающую обнуление (по умолчанию), короткую функцию NNBD, в настоящее время можно найти по адресу https://nullsafety.dartpad.dev/.
Имейте в виду, что вы можете прочитать полную спецификацию здесь и полную дорожную карту здесь. Теперь для Dart официально объявлено о нулевой безопасности звука.
2.1. Что означает значение по умолчанию, не допускающее значения NULL?
void main() {
String word;
print(word); // illegal
word = 'Hello, ';
print(word); // legal
}
Как вы можете видеть выше, переменная, не допускающая значения NULL по умолчанию, означает, что каждая переменная, которая обычно объявлена, не может бытьnull
. Следовательно, любая операция доступа к переменной до того, как она была назначена, является незаконной.
Дополнительно присвоениеnull
в переменную, не допускающую значения NULL, также не допускается:
void main() {
String word;
word = null; // forbidden
world = 'World!'; // allowed
}
2.1.1. Как это мне помогает?
Если переменная не допускает значения NULL, вы можете быть уверены, что она никогда не будетnull
. Благодаря этому вам никогда не нужно проверять его заранее.
int number = 4;
void main() {
if (number == null) return; // redundant
int sum = number + 2; // allowed because number is also non-nullable
}
2.1.2. Помнить
Поля экземпляра в классах должны быть инициализированы, если они не допускают значения NULL:
class Foo {
String word; // forbidden
String sentence = 'Hello, World!'; // allowed
}
Увидеть late
ниже, чтобы изменить это поведение.
2.2. Обнуляемые типы (?
)
Вы можете использовать типы, допускающие значение NULL, добавив вопросительный знак?
к типу переменной:
class Foo {
String word; // forbidden
String? sentence; // allowed
}
Обнуляемым переменная не должна быть инициализирована, прежде чем он может быть использован. Он инициализируется какnull
по умолчанию:
void main() {
String? word;
print(word); // prints null
}
2.2.2. !
Добавление !
к любой переменной e
выдаст ошибку времени выполнения, еслиe
имеет значение NULL, и в противном случае преобразовать его в значение, не допускающее значения NULLv
.
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
}
2.3. late
Ключевое слово late
может использоваться для обозначения переменных, которые будут инициализированы позже, то есть не при их объявлении, а при обращении к ним. Это также означает, что у нас могут быть поля экземпляра, не допускающие значения NULL, которые инициализируются позже:
class ExampleState extends State {
late final String word; // non-nullable
@override
void initState() {
super.initState();
// print(word) here would throw a runtime error
word = 'Hello';
}
}
Доступ word
перед его инициализацией вызовет ошибку времени выполнения.
2.3.1. 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
.
2.4. required
Ранее аннотация (@required
), теперь встроенный как модификатор. Это позволяет пометить любой именованный параметр (для функций или классов) какrequired
, что делает их не допускающими значения NULL:
void allowed({required String word}) => null;
Это также означает, что если параметр не должен допускать значения NULL, его необходимо пометить какrequired
или иметь значение по умолчанию:
void allowed({String word = 'World'}) => null;
void forbidden({int x}) // compile-time error because x can be null (unassigned)
=>
null;
Любой другой именованный параметр должен иметь значение NULL:
void baz({int? x}) => null;
2.5. ?[]
Нулевой осведомленный ?[]
добавлен оператор индексации []
:
void main() {
List<int>? list = [1, 2, 3];
int? x = list?[0]; // 1
}
См. Также эту статью о решении синтаксиса.
2.5.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);
}
2.6. 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
Насколько я понимаю, программисты не должны использовать его.
3. Узнать больше
Вы можете прочитать официальную статью о нулевой безопасности звука.
Кроме того, как упоминалось в начале, вы можете играть с ним на DartPad.
если вы хотите, чтобы это поле было обязательным, используйте обязательное ключевое слово, в противном случае вам нужно только поставить «?». как это
const phonefield({
Key? key,required this.onchanged,
}) : super(key: key);
final ValueChanged<String>onchanged;