Операторы is и as
Часть раздела Объектно-ориентированное программирование путешествия по Dart на Coddy — урок 60 из 110.
Хотя runtimeType сообщает вам точный тип, Dart предоставляет два оператора, которые более практичны для проверки типов и приведения типов: is и as.
Оператор is проверяет, является ли объект объектом определенного типа, и возвращает логическое значение. В отличие от runtimeType, он также возвращает true для родительских типов:
class Animal {}
class Dog extends Animal {}
void main() {
Animal pet = Dog();
print(pet is Dog); // true
print(pet is Animal); // true (Dog ЯВЛЯЕТСЯ Animal)
print(pet is String); // false
}Когда вы используете is внутри инструкции if, Dart автоматически повышает тип, позволяя вам обращаться к членам подкласса без явного приведения типов:
void handleAnimal(Animal animal) {
if (animal is Dog) {
// Dart знает, что animal здесь — это Dog
animal.bark(); // Можно вызывать методы, специфичные для Dog
}
}Оператор as явно приводит объект к определенному типу. Используйте его, когда вы уверены в типе:
Animal pet = Dog();
Dog myDog = pet as Dog; // Приведение к Dog
myDog.bark();Будьте осторожны с as — если приведение типов не удастся, оно выбросит исключение. Поэтому сочетание is с продвижением типов часто безопаснее, чем прямое использование as. Вы также можете использовать is!, чтобы проверить, что объект не является объектом определенного типа.
Задание
ЛегкоДавайте создадим систему обработки фигур, которая использует операторы is и as для идентификации и работы с различными типами фигур. Вы создадите иерархию фигур и напишете функции, которые проверяют типы и безопасно обращаются к свойствам, специфичным для конкретного типа.
Вы организуете свой код в двух файлах:
shapes.dart: Определите здесь вашу иерархию фигур:- Класс
Shapeсо свойствомString nameи конструктором. Включите методdescribe(), который выводит'$name is a shape' - Класс
Circle, который расширяетShapeдополнительным свойствомdouble radius. Добавьте методgetCircleInfo(), который выводит'Circle with radius: $radius' - Класс
Rectangle, который расширяетShapeдополнительными свойствамиdouble widthиdouble height. Добавьте методgetRectangleInfo(), который выводит'Rectangle: $width x $height'
- Класс
main.dart: Импортируйте файл с фигурами и создайте функциюprocessShape(Shape shape), которая:- Сначала вызывает
describe()для фигуры - Использует
isдля проверки, является ли фигура объектомCircle— если да, используйте продвижение типов (type promotion) для вызоваgetCircleInfo() - Использует
isдля проверки, является ли фигура объектомRectangle— если да, используйте операторasдля приведения типа и вызоваgetRectangleInfo() - Использует
is!для проверки, что фигура НЕ являетсяCircleи НЕ являетсяRectangle— если это так, выведите'Unknown shape type'
main():- Создайте
Circleс именем'Round'и радиусом5.0и передайте его вprocessShape() - Выведите пустую строку
- Создайте
Rectangleс именем'Box', шириной4.0и высотой3.0и передайте его вprocessShape() - Выведите пустую строку
- Создайте базовый объект
Shapeс именем'Mystery'и передайте его вprocessShape()
- Сначала вызывает
Эта задача демонстрирует оба подхода: использование is с автоматическим продвижением типов для Circle и использование as для явного приведения типов для Rectangle. Вы также увидите, как is! помогает идентифицировать фигуры, которые не соответствуют ни одному конкретному подтипу.
Ожидаемый результат:
Round is a shape
Circle with radius: 5.0
Box is a shape
Rectangle: 4.0 x 3.0
Mystery is a shape
Unknown shape typeШпаргалка
Оператор is проверяет, является ли объект определенным типом, и возвращает логическое значение. Он также возвращает true для родительских типов:
class Animal {}
class Dog extends Animal {}
void main() {
Animal pet = Dog();
print(pet is Dog); // true
print(pet is Animal); // true (Dog ЯВЛЯЕТСЯ Animal)
print(pet is String); // false
}Когда вы используете is внутри оператора if, Dart автоматически повышает тип (type promotion), позволяя вам обращаться к членам подкласса без явного приведения типов:
void handleAnimal(Animal animal) {
if (animal is Dog) {
// Dart знает, что animal здесь — это Dog
animal.bark(); // Можно вызывать методы, специфичные для Dog
}
}Оператор as явно приводит объект к определенному типу:
Animal pet = Dog();
Dog myDog = pet as Dog; // Приведение к Dog
myDog.bark();Будьте осторожны с as — если приведение не удастся, возникнет исключение. Сочетание is с повышением типа часто безопаснее, чем прямое использование as.
Используйте is!, чтобы проверить, что объект не является определенным типом:
if (animal is! Dog) {
print("Not a dog");
}Попробуйте сами
import 'shapes.dart';
// TODO: Создайте функцию processShape(Shape shape), которая:
// 1. Сначала вызывает describe() для shape
// 2. Использует 'is', чтобы проверить, является ли shape объектом Circle — если да, использует продвижение типов (type promotion) для вызова getCircleInfo()
// 3. Использует 'is', чтобы проверить, является ли shape объектом Rectangle — если да, использует оператор 'as' для приведения типа и вызова getRectangleInfo()
// 4. Использует 'is!', чтобы проверить, что shape НЕ является Circle и НЕ является Rectangle — если это так, выводит "Unknown shape type"
void main() {
// TODO: Создайте Circle с именем 'Round' и радиусом 5.0 и передайте его в processShape()
// TODO: Выведите пустую строку
// TODO: Создайте Rectangle с именем 'Box', шириной 4.0 и высотой 3.0 и передайте его в processShape()
// TODO: Выведите пустую строку
// TODO: Создайте базовый Shape с именем 'Mystery' и передайте его в processShape()
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыБиблиотеки и импортВведение в ООПКлассы и объектыКлючевое слово thisМетодыПеременные экземпляраОсновы конструкторовИтоги — Простой калькулятор4Null-безопасность
Введение в Null-безопасностьNullable и Non-Nullable типыОператоры ? и !Ключевое слово Late и Null-безопасностьNull-aware операторыNull-безопасность в классахИтоги — Система профилей пользователей7Абстрактные классы и интерфейсы
Абстрактные классыАбстрактные методыИнтерфейсы в DartНеявные интерфейсыРеализация против наследованияМножественные интерфейсыИтоги — Калькулятор фигур10Коллекции и обобщения
Обзор List, Set, MapТипобезопасные коллекцииОбобщенные классыОбобщенные методыОграничения обобщенийIterable и IteratorИтоги: Обобщенное хранилище13Продвинутые концепции ООП
Композиция против наследованияМетоды расширенияВызываемые классыЗапечатанные классы (Dart 3)Записи (Dart 3)Паттерны и сопоставление (3.0)Перечисления с методами16Проект: Управление библиотекой
Обзор проектаКлассы Book и User2Конструкторы в Dart
Конструктор по умолчаниюИменованные конструкторыСписки инициализацииКонстантные конструкторыФабричные конструкторыПеренаправляющие конструкторыИтоги — Shape Builder5Инкапсуляция
Публичные и приватные членыСоглашение о префиксе _Приватность на уровне библиотекГеттеры и сеттеры: подробный разборСкрытие данныхИтоги — Записи о студентах8Mixins
Введение в MixinsСоздание MixinsИспользование нескольких MixinsКлючевое слово on в MixinsMixin и наследованиеMixin и интерфейсИтоги: Система животных11Специальные методы
Переопределение toString()Переопределение hashCode и ==Интерфейс ComparableМетод call()Переопределение noSuchMethodПовторение — Пользовательская коллекция14Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн ObserverПаттерн Strategy3Свойства классов
Члены экземпляра и статические членыПоля Final и ConstПеременные LateСтатические методы и поляГеттеры и сеттерыИтоги — Менеджер банковского счета6Наследование
Основы наследованияКлючевое слово superПереопределение методовАннотация @overrideКлючевое слово final для классовКонструкторы и наследованиеИтоги: Иерархия сотрудников9Полиморфизм
Основы полиморфизмаПолиморфизм через интерфейсыПроверка типов во время выполненияОператоры is и asКлючевое слово covariantИтоги — Обработчик платежей12Асинхронное ООП
Futures и async/awaitОсновы StreamsКонтроллеры StreamАсинхронные конструкторыАсинхронность в методах классовИтоги — Data Fetcher15Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикПаттерн Репозиторий