Обзор трёх операторов (as /is/is!)
| Оператор | Описание работы |
|---|---|
as | Принудительное преобразование типа; также используется для задания псевдонима библиотеки |
is | Проверка типа: возвращает true, если объект относится к указанному типу |
is! | Проверка типа: возвращает true, если объект не относится к указанному типу |
Условие истинности выражения obj is T: объект obj реализует или наследует тип T (включая родительские классы, интерфейсы и нулевые типы).
Пример: выражение Любой объект is Object? всегда даёт true.
Оператор is
Безопасная проверка типа
Проверяет тип объекта во время выполнения программы; если результат равен true, внутри блока кода объект можно использовать как соответствующий тип без ручного преобразования. Если объект равен null или типы не совпадают, возвращается false, исключений не возникает.
В примере ниже используются объекты классов. Если вы ещё не изучали классы, считайте их шаблонами для создания данных.
class Person {
String firstName = '';
}
class Employee extends Person {}
void main() {
dynamic employee = Employee();
// Проверка типа через is
if (employee is Person) {
// При входе в ветвь переменная автоматически распознаётся как Person
employee.firstName = "Jack";
print(employee.firstName); // Выведет Jack
}
dynamic emptyObj = null;
if (emptyObj is Person) {
// Код не выполнится, null не соответствует типу Person
print("Совпадение найдено");
}
}Code language: Dart (dart)
В данном коде определён класс Person, а затем наследующий его класс Employee.
В коде оператор is проверяет, является ли объект экземпляром Person. При истинном результате внутри фигурных скобок объект используется напрямую как Person. Это возможно благодаря динамическому типу в записи dynamic employee = Employee();.
Во втором примере dynamic emptyObj = null; переменная хранит значение null, поэтому выражение emptyObj is Person даёт false, код внутри блока не запустится.
Оператор is!
Обратная проверка типа
Синтаксис:
переменная is! тип
Фактически это то же самое, что инверсия результата оператора is.
Эквивалент записи !(переменная is тип), проверяет, что объект не является целевым типом.
Рассмотрим пример:
class Person {
String name = '';
}
void main() {
dynamic obj = "текст";
if (obj is! Person) {
print("obj не относится к типу Person");
}
}Code language: Dart (dart)
В данном примере выполнится код внутри блока и выведется строка «obj не относится к типу Person», потому что obj не является экземпляром, созданным по шаблону Person.
Оператор as
Принудительное преобразование типа
Способ применения:
(переменная as целевой_тип).свойство/методCode language: JavaScript (javascript)
Используйте этот оператор только если вы на 100% уверены, что объект имеет нужный тип. В противном случае во время выполнения возникнет исключение. Для устойчивости программы не рекомендуется частое использование as.
class Teacher {
String name = '';
}
void main() {
dynamic jason = Teacher();
// Принудительное преобразование в Teacher для доступа к свойству
(jason as Teacher).name = "Jason";
print((jason as Teacher).name); // Jason
}Code language: Dart (dart)
Результат вывода примера — строка Jason
Мы напрямую создаём экземпляр Teacher через dynamic jason = Teacher();, поэтому точно знаем, что переменная имеет тип Teacher, ошибок не возникнет.

Если написать код ниже, появится ошибка.
class Teacher {
String name = '';
}
class Car {
String name = '';
}
void main() {
dynamic jason = Teacher();
// Принудительное преобразование в Car для доступа к свойству
(jason as Car).name = "Jason";//❌ошибка
print((jason as Car).name); //❌ошибка
}Code language: Dart (dart)
Ошибка возникает, потому что изначально jason — объект Teacher, но мы пытаемся принудительно преобразовать его в тип Car.
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Unhandled exception:
type 'Teacher' is not a subtype of type 'Car' in type cast
#0 main (file:///D:/dartdemo/firstdart/bin/firstdart.dart:12:10)
#1 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:314:19)
#2 _RawReceivePort._handleMessage (dart:isolate-patch/isolate-patch.dart:193:12)Code language: PHP (php)
Основное сравнение as и is
// Вариант 1: принудительное преобразование через as
(employee as Person).firstName = 'Bob';
// Вариант 2: предварительная проверка через is перед использованием
if (employee is Person) {
employee.firstName = 'Bob';
}Code language: JavaScript (javascript)
Поведение при employee равном null или не являющемся объектом типа Person:
- Вариант с as: выбрасывается исключение
CastError, программа аварийно завершается; - Вариант с is: ветвь if не выполняется, ошибок нет, никаких действий не происходит.
Хотя код получается немного длиннее, предпочитайте проверку через is — это повышает устойчивость программы.
Второе назначение оператора as
Второе назначение оператора as
as используется не только для преобразования типов: при импорте библиотек с его помощью задают псевдоним библиотеки
import 'dart:math' as math;
void main() {
// Обращение к классам и методам через псевдоним библиотеки
print(math.pi); // Выведет 3.141592653589793
}Code language: JavaScript (javascript)
Итоговый полный пример
class Animal {}
class Cat extends Animal {}
void main() {
dynamic obj = Cat();
// 1. Проверка через is
if (obj is Animal) {
print("obj относится к типу Animal");
}
// 2. Обратная проверка через is!
if (obj is! String) {
print("obj не является строкой");
}
// 3. Принудительное преобразование через as
Animal a = obj as Animal;
// Ошибочный пример, вызывающий сбой программы
dynamic str = "hello";
// Animal error = str as Animal; // Возникает CastError
}Code language: JavaScript (javascript)