Условное приведение с помощью as?
Выполняйте приведение, которое при неудаче возвращает необязательное значение.
«Условное приведение с помощью as?» — бесплатный урок Swift Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Swift Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Swift Academy содержит 4 уроков всего.
Условное приведение
Оператор условного приведения as? пытается выполнить понижающее приведение и возвращает опциональное значение: обёрнутое значение при успехе или 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 a: Animal = Dog(name: "Rex")
let maybe = a as? Dog
print(maybe != nil)Результат является опциональным значением
Поскольку приведение может завершиться неудачей, тип результата — Dog?, а не Dog. Перед использованием значение необходимо распаковать.
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")
let maybe: Dog? = a as? Dog
print(type(of: maybe))Распаковка с помощью if let
Идиоматичный способ использовать as? — поместить его в привязку if let, тело которой выполняется только при успешном приведении.
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())
} else {
print("Not a dog")
}Неудачное приведение возвращает nil
Если экземпляр не имеет целевого типа, as? возвращает nil, а тело if let пропускается.
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")
if let dog = a as? Dog {
print(dog.bark())
} else {
print("That is not a dog")
}Сочетание с guard let
Можно также использовать guard let, чтобы выполнить приведение в начале и выйти, если оно завершится неудачей, оставив основной путь выполнения без лишних отступов.
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" }
}
func describe(_ a: Animal) {
guard let cat = a as? Cat else {
print("Not a cat")
return
}
print(cat.meow())
}
describe(Cat(name: "Mia"))
describe(Dog(name: "Rex"))Условное приведение в циклах
Перебор смешанного массива с условным приведением каждого элемента — удобный способ безопасно обрабатывать разные подклассы.
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"), Dog(name: "Buddy")]
for a in zoo {
if let dog = a as? Dog {
print(dog.bark())
}
}Приведение к протоколам
as? также проверяет соответствие протоколу: если экземпляр соответствует протоколу, оператор возвращает значение, иначе — nil.
protocol Greeter { func greet() -> String }
class Person: Greeter { func greet() -> String { return "Hi" } }
class Rock {}
let items: [Any] = [Person(), Rock()]
for item in items {
if let g = item as? Greeter { print(g.greet()) }
}Оператор объединения с nil после приведения
Можно объединить 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 = Cat(name: "Mia")
let sound = (a as? Dog)?.bark() ?? "unknown sound"
print(sound)Цепочка вызовов при опциональном приведении
Опциональная цепочка позволяет вызвать метод у результата приведения; всё выражение равно 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 a: Animal = Dog(name: "Rex")
let bark = (a as? Dog)?.bark()
print(bark as Any)Почему предпочтительно условное приведение
as? никогда не вызывает сбой: неудачное приведение просто даёт 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 unknown: Animal = Cat(name: "Mia")
let result = unknown as? Dog
print("Crashes? No. Value is nil:", result == 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" }
}
func sound(of a: Animal) -> String {
if let d = a as? Dog { return d.bark() }
if let c = a as? Cat { return c.meow() }
return "silence"
}
print(sound(of: Dog(name: "Rex")))
print(sound(of: Cat(name: "Mia")))Быстрая проверка
Вспомните тип результата условного приведения.
Итоги: условное приведение с помощью as?
Вы узнали, что as? выполняет безопасное понижающее приведение и возвращает опциональное значение, что if let и guard let распаковывают успешный результат, а оператор никогда не вызывает сбой, поскольку при неудаче просто возвращается 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 pets: [Animal] = [Dog(name: "Rex"), Cat(name: "Mia")]
for p in pets {
if let d = p as? Dog { print(d.bark()) } else if let c = p as? Cat { print(c.meow()) }
}Часто задаваемые вопросы
Урок «Условное приведение с помощью as?» бесплатный?
Да — полный текст урока «Условное приведение с помощью as?» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Swift Academy, подпишись на CoddyKit PRO. Курс Swift Academy содержит 4 уроков всего.
Чему я научусь в уроке «Условное приведение с помощью as?»?
Выполняйте приведение, которое при неудаче возвращает необязательное значение. Ты практикуешь Swift Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Swift Academy?
Предыдущий опыт не требуется. Swift Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.
Сколько времени занимает урок «Условное приведение с помощью as?»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Swift Academy?
Да. Каждый урок Swift Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Основы повышающего и понижающего приведения
- Условное приведение с помощью as?
- Принудительное приведение с помощью as! и его риски
- Проверка типов с помощью is