0Pricing
Swift Academy · Урок

Основы повышающего и понижающего приведения

Переходите между типами суперкласса и подкласса.

«Основы повышающего и понижающего приведения» — бесплатный урок Swift Academy на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Swift Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Swift Academy содержит 4 уроков всего.

Обзор приведения типов

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

class Animal {
    let name: String
    init(name: String) { self.name = name }
}
class Dog: Animal {
    func bark() -> String { return name + " says Woof" }
}
class Cat: Animal {
    func meow() -> String { return name + " says Meow" }
}
let d = Dog(name: "Rex")
print(d.bark())

Иерархия классов

Для приведения типов нужна иерархия. Здесь Dog и Cat наследуются от Animal. Dog является Animal.

class Animal {
    let name: String
    init(name: String) { self.name = name }
}
class Dog: Animal {
    func bark() -> String { return name + " says Woof" }
}
class Cat: Animal {
    func meow() -> String { return name + " says Meow" }
}
let pet: Animal = Dog(name: "Rex")
print(pet.name)

Повышающее приведение с помощью as

Повышающее приведение рассматривает экземпляр подкласса как экземпляр его базового класса. Оно всегда успешно, поэтому используется обычный оператор as.

class Animal {
    let name: String
    init(name: String) { self.name = name }
}
class Dog: Animal {
    func bark() -> String { return name + " says Woof" }
}
class Cat: Animal {
    func meow() -> String { return name + " says Meow" }
}
let dog = Dog(name: "Rex")
let asAnimal = dog as Animal
print(asAnimal.name)

Зачем нужно повышающее приведение

Повышающее приведение удобно, когда нужно хранить разные подклассы вместе, например в одном массиве, типизированном общим базовым классом.

class Animal {
    let name: String
    init(name: String) { self.name = name }
}
class Dog: Animal {
    func bark() -> String { return name + " says Woof" }
}
class Cat: Animal {
    func meow() -> String { return name + " says Meow" }
}
let zoo: [Animal] = [Dog(name: "Rex"), Cat(name: "Mia")]
for a in zoo { print(a.name) }

Повышающее приведение всегда безопасно

Поскольку каждый экземпляр подкласса также является допустимым экземпляром базового класса, компилятор принимает as для повышающего приведения без риска сбоя.

class Animal {
    let name: String
    init(name: String) { self.name = name }
}
class Dog: Animal {
    func bark() -> String { return name + " says Woof" }
}
class Cat: Animal {
    func meow() -> String { return name + " says Meow" }
}
let cat = Cat(name: "Mia")
let animal = cat as Animal
print("Treated as Animal:", animal.name)

Потеря доступа после повышающего приведения

После сохранения значения как экземпляра базового класса можно вызывать только его члены. Специфичный для Dog метод bark() скрыт, пока вы не выполните понижающее приведение.

class Animal {
    let name: String
    init(name: String) { self.name = name }
}
class Dog: Animal {
    func bark() -> String { return name + " says Woof" }
}
class Cat: Animal {
    func meow() -> String { return name + " says Meow" }
}
let a: Animal = Dog(name: "Rex")
print(a.name)
// a.bark() would not compile here

Введение в понижающее приведение

Понижающее приведение работает в обратную сторону: ссылка на базовый класс рассматривается как ссылка на конкретный подкласс, чтобы снова получить доступ к его членам. Такое приведение может завершиться неудачей, поэтому нужны as? или as!.

class Animal {
    let name: String
    init(name: String) { self.name = name }
}
class Dog: Animal {
    func bark() -> String { return name + " says Woof" }
}
class Cat: Animal {
    func meow() -> String { return name + " says Meow" }
}
let a: Animal = Dog(name: "Rex")
if let dog = a as? Dog {
    print(dog.bark())
}

Почему понижающее приведение может завершиться неудачей

Компилятор не может гарантировать, что данный Animal действительно является Dog. Это может быть Cat. Поэтому понижающее приведение необходимо проверять.

class Animal {
    let name: String
    init(name: String) { self.name = name }
}
class Dog: Animal {
    func bark() -> String { return name + " says Woof" }
}
class Cat: Animal {
    func meow() -> String { return name + " says Meow" }
}
let a: Animal = Cat(name: "Mia")
let maybeDog = a as? Dog
print("Is it a Dog?", maybeDog != nil)

Понижающее приведение в цикле

Распространённый подход: перебрать массив базового класса и выполнить понижающее приведение каждого элемента, чтобы обрабатывать подклассы по-разному.

class Animal {
    let name: String
    init(name: String) { self.name = name }
}
class Dog: Animal {
    func bark() -> String { return name + " says Woof" }
}
class Cat: Animal {
    func meow() -> String { return name + " says Meow" }
}
let zoo: [Animal] = [Dog(name: "Rex"), Cat(name: "Mia")]
for a in zoo {
    if let dog = a as? Dog { print(dog.bark()) }
    if let cat = a as? Cat { print(cat.meow()) }
}

Сравнение повышающего и понижающего приведения

Повышающее приведение (as) ведёт к базовому типу и всегда успешно. Понижающее приведение (as? или as!) ведёт к конкретному типу и может завершиться неудачей.

class Animal {
    let name: String
    init(name: String) { self.name = name }
}
class Dog: Animal {
    func bark() -> String { return name + " says Woof" }
}
class Cat: Animal {
    func meow() -> String { return name + " says Meow" }
}
let d = Dog(name: "Rex")
let up = d as Animal
let down = up as? Dog
print(up.name, down?.bark() ?? "no")

Приведение возможно только внутри иерархии

Приводить можно только связанные типы из одной иерархии. Несвязанные типы нельзя привести один к другому.

class Animal {
    let name: String
    init(name: String) { self.name = name }
}
class Dog: Animal {
    func bark() -> String { return name + " says Woof" }
}
class Cat: Animal {
    func meow() -> String { return name + " says Meow" }
}
let a: Animal = Dog(name: "Rex")
print(a is Animal)
print(a is Dog)

Быстрая проверка

Вспомните, какое направление приведения всегда успешно.

Итоги: повышающее и понижающее приведение

Вы узнали, что приведение работает внутри иерархии классов, что повышающее приведение с помощью as к базовому типу всегда успешно, а понижающее приведение к конкретному подклассу может завершиться неудачей и поэтому требует проверяемых операторов, которые будут рассмотрены далее.

class Animal {
    let name: String
    init(name: String) { self.name = name }
}
class Dog: Animal {
    func bark() -> String { return name + " says Woof" }
}
class Cat: Animal {
    func meow() -> String { return name + " says Meow" }
}
let pets: [Animal] = [Dog(name: "Rex"), Cat(name: "Mia")]
for p in pets {
    if let d = p as? Dog { print(d.bark()) } else { print(p.name) }
}

Часто задаваемые вопросы

Урок «Основы повышающего и понижающего приведения» бесплатный?

Да — полный текст урока «Основы повышающего и понижающего приведения» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Swift Academy, подпишись на CoddyKit PRO. Курс Swift Academy содержит 4 уроков всего.

Чему я научусь в уроке «Основы повышающего и понижающего приведения»?

Переходите между типами суперкласса и подкласса. Ты практикуешь Swift Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Swift Academy?

Предыдущий опыт не требуется. Swift Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.

Сколько времени занимает урок «Основы повышающего и понижающего приведения»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Swift Academy?

Да. Каждый урок Swift Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Основы повышающего и понижающего приведения
  2. Условное приведение с помощью as?
  3. Принудительное приведение с помощью as! и его риски
  4. Проверка типов с помощью is
← Назад к Swift Academy