Преобразование типов

Последнее обновление: 07.04.2023

Нередко может возникнуть необходимость выполнить преобразования типов - когда у нас есть объект одного типа, но по логике программы требуется объект другого типа. Одни преобразования типов Dart может выполнять автоматически неявно, другие преобразования надо выполнять явно. Иногда преобразования возможны, иногда невозможны. Рассмотрим подобные ситуации.

Неявные преобразования

Объект производного класса одновременно является объектом базового класса. Поэтому Dart автоматически неявно может преобразовать объекты производных типов в базовый тип. Например, возьмем следующие классы:

// класс человека 
class Person{
  
    String name;
    Person(this.name);
    void display() => print("Person $name");
}
// класс работника
class Employee extends Person{

    String company;
    Employee(super.name, this.company);
    @override
    void display() => print("Employee $name works in $company");
}
// класс студента
class Student extends Person{

    String university;
    Student(super.name, this.university);
    @override
    void display() => print("Student $name studies in $university");
}

Здесь есть базовый класс Person, который представляет человека и который в поле name хранит имя. И есть два производных класса - Employee и Student. Employee представляет работника и с помощью поля company хранит компанию, где он работает. А класс Student представляет студента и определяет поле university для хранения вуза, где учится студент. Поскольку Student и Employee унаследованы от Person, то любой объект классов Student и Employee является в то же время объектом Person. Поэтому переменной типа Person мы можем присвоить объекты производных классов:

void main (){
     
    Person bob = Employee("Bob", "Google");
    bob.display();  // Employee Bob works in Google

    Person sam = Student("Sam", "MIT");
    sam.display();  // Student Sam studies in MIT
} 

В данном случае переменная bob представляет тип Person, но в реальности хранит объект Employee. Таким образом, объект Employee неявно преобразуется в тип Person. Однако если мы вызовем у этого объекта метод display:

bob.display();  // Employee Bob works in Google

то будет выполняться реализация метода display именно из класса Employee, потому что переменная bob в реальности указывается на объект Employee. То же самое касается переменной sam, которая представляет тип Person, но хранит ссылку на объект Student./p>

Подобное обстоятел благодаря наследованию, там, где требуется объект базового класса, мы можем использовать объект производного класса. Например, пусть у нас будет функция, которая принимает в качестве параметра объект Person:

void printName(Person person)
{
    print(person.name);
}

void main (){
     
    Person tom = Person("Tom");
    Employee bob = Employee("Bob", "Google");
    Student  sam = Student("Sam", "MIT");
    printName(tom);
    printName(bob); // неявное преобразование от Employee к Person
    printName(sam); // неявное преобразование от Student к Person
} 

Поскольку Student и Employee - наследники класса Person, то мы можем передать их объекты в функцию printName, которая принимает объекты Person.

Явные преобразования и оператор as

Как мы выше увидели, преобразования от производного класса (Employee/Student) к базовому (Person) производятся автоматически. Но что будет противоположном направлении - от базового к производному? Поскольку не каждый объект базового класса может представлять производный тип, то подобные преобразовании нам надо выполнять явно - с помощью оператора as:

объект as тип;

Слева от оператора указывается объект, который надо преобразовать, а справа - тип, в который надо преобразовать. Результат операции - преобразованный объект. Например:

void printCompany(Person person)
{
    Employee emp = person as Employee; // преобразуем Person в Employee
    print(emp.company);
}

void main (){
     
    Person bob = Employee("Bob", "Google");
    printCompany(bob);  // Google
} 

Здесь функция printCompany принимает объект Person и преобразует его в тип Employee. После чего у преобразованного объекта выводится компания:

Employee emp = person as Employee;

Может возникнуть вопрос, зачем нам нам передавать объект Employee, который преобразуется неявно в Person, а в функции его обратно преобразовывать в Employee? Дело в том, что мы можем получать данные извне и точно не знать, какой именно производный тип представляет объект. И в этом случае мы получаем данные в виде объекта базового класса Person.

Однако с этим связана другая проблема - теоретически в функцию printCompany мы можем передать объект Person, который не является объектом Employee. Например:

void printCompany(Person person)
{
    Employee emp = person as Employee;
    print(emp.company);
}

void main (){
     
    Person tom = Person("Tom");
    printCompany(tom);  // ! Ошибка
} 

Поскольку здесь переменная tom не представляет объект Employee, то соответственно мы НЕ можем выполнить преобразование в Employee и получить поле company, поэтому выполнение функции завершится ошибкой. И в этом случае перед явным преобразованием необходимо проверять тип с помощью оператора is.

Проверка типа и оператор is

Оператор is возвращает true, если объект представляет определенный тип:

объект is тип

Также есть противоположный оператор - is!, который возвращает true, если объект НЕ представляет определенный тип:

объект is! тип

Применим данный оператор:

void printCompany(Person person)
{
    if(person is Employee){     // если person представляет класс Employee

        Employee emp = person as Employee;
        print(emp.company);
    } 
    else{
        print("person is not Employee");
    }
}

void main (){
     
    Person bob = Employee("Bob", "Google");
    printCompany(bob);  // Google

    Person tom = Person("Tom");
    printCompany(tom);  // person is not Employee
} 

Подобным образом можно проверять на другие типы:

void printPerson(Person person)
{
    print(person.name);
    if(person is Employee){     // если тип - Employee

        Employee emp = person as Employee;
        print(emp.company);
    } 
    else if(person is Student){ // если тип - Student

        Student student = person as Student;
        print(student.university);
    } 
}

void main (){
     
    Person tom = Person("Tom");
    printPerson(tom);  // person is not Employee

    Person bob = Employee("Bob", "Google");
    printPerson(bob);  // Google

    Person sam = Student("Sam", "MIT");
    printPerson(sam);  // MIT
} 
Дополнительные материалы
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850