Menu
Coddy logo textTech

Операторы 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!, чтобы проверить, что объект не является объектом определенного типа.

challenge icon

Задание

Легко

Давайте создадим систему обработки фигур, которая использует операторы 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()
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование