[Разработка под iOS, Swift] Разбираемся с Opaque Return Types в Swift (перевод)
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Привет, Хабр. В рамках стартующего в феврале курса «iOS Developer. Professional»подготовили для вас перевод полезного материала.
Также предлагаем принять участие в открытом вебинаре на тему «Пишем приложение на SwiftUI и Combine». Участники вместе с экспертом разберут, что такое SwiftUI и фреймворк Combine, а также как с их помощью создать небольшое приложение.
Вы также можете прочитать эту статью в моем блоге Xcoding With Alfian, перейдя по ссылке.Opaque return types (непрозрачные типы) — это новая языковая конструкция, представленная Apple в Swift 5.1. Их можно использовать для возврата некоторого (some) значения функции (function)/метода (method) и свойства (property), не раскрывая конкретный тип значения клиенту, который вызывает API. Тип возврата будет некоторым типом, реализующим протокол (protocol). С помощью этого решения API-интерфейс модуля больше не должен публично раскрывать базовый внутренний возвращаемый тип метода, ему просто нужно вернуть opaque type протокола с помощью ключевого слова some. Компилятор Swift также сможет сохранить базовую идентичность (identity) возвращаемого типа, в отличии от варианта с использованием протокола в качестве возвращаемого типа. SwiftUI использует opaque return typesвнутри своего протокола View, который возвращает some View в свойстве body.Вот некоторые из важных возможностей, предоставляемых opaque return types, которые закрепят их в нашем наборе инструментов и будут использоваться всякий раз, когда мы захотим создать API с использованием Swift:
- Возможность предоставить определенный тип протокола, не раскрывая конкретный (concrete) тип вызывающему API для лучшей инкапсуляции (encapsulation).
- Поскольку API не предоставляет вызывающей стороне приватный конкретный тип возвращаемого значения, клиенту не нужно беспокоиться о том, изменятся ли в будущем базовые типы, если он реализует базовый протокол.
- Предоставляет надежные гарантии базовой идентичности, возвращая определенный тип во время выполнения. Компромисс заключается в потере гибкости при возврате значений нескольких типов, предлагаемых с использованием протокола в качестве типа возврата.
- Из-за строгой гарантии возврата определенного типа протокола. Функция может возвращать opaque protocol type, который имеет в требовании Self или associated type.
- Протокол оставляет решение возвращать тип вызывающему объекту функции. В обратном случае для opaque return types сама функция принимает решение для конкретного типа возвращаемого значения, если она реализует протокол.
Пример использования Opaque return typesЧтобы понять больше о opaque return type и почему он отличается от простого использования протокола в качестве возвращаемого типа, давайте погрузимся в код примеров того, как мы можем его использовать.Объявление протокола с associatedtypeДопустим, у нас есть протокол под названием MobileOS. Этот протокол имеет associatedtype (связанный тип) называемый Version и свойство, позволяющее получить Version, для конкретного типа, который необходимо реализовать.
protocol MobileOS {
associatedtype Version
var version: Version { get }
init(version: Version)
}
Реализация конкретных типов протоколаОпределим два конкретных типа для этого протокола: iOS и Android. Оба они имеют разную семантику версий. IOS использует тип float, а Android использует String (хотя недавно они изменили его в Android 10).
struct iOS: MobileOS {
var version: Float
}
struct Android: MobileOS {
var version: String
}
Создание функции для возврата типа протоколаПредположим, мы хотим создать новую функцию, которая возвращает протокол MobileOS в качестве возвращаемого типа. Наивный подход заключается в том, чтобы написать это так:Решение 1 (возвращает тип протокола):
func buildPreferredOS() -> MobileOS {
return iOS(version: 13.1)
}
// ОШИБКА компилятора
Протокол 'MobileOS' может использоваться только как общее ограничение,
потому что у него есть требования к типу Self или associated type.
Как видите, компилятор выдает ошибку, потому что наш протокол имеет ограничение, которое использует associatedtype. Компилятор не сохраняет идентичность типа возвращаемого значения при использовании протокола в качестве возвращаемого типа. Давайте попробуем другое решение, которое напрямую возвращает конкретный тип.Решение 2 (возвращает конкретный тип):
func buildPreferredOS() -> iOS {
return iOS(version: 13.1)
}
// Сборка прошла успешно
Это решение работает, но, как вы можете видеть, API теперь передает вызывающей стороне конкретный тип. Этот код потребует серьезного рефакторинга, если в будущем мы передумаем и вернем Android в качестве возвращаемого типа функции.Решение 3 (Generic Function Return)
func buildPreferredOS<T: MobileOS>(version: T.Version) -> T {
return T(version: version)
}
let android: Android = buildPreferredOS(version: "Jelly Bean")
let ios: iOS = buildPreferredOS(version: 5.0)
Да, этот подход работает элегантно. Но теперь сторона, вызывающая API, должна указать конкретный тип возвращаемой функции. Если мы действительно хотим, чтобы вызывающей стороне не нужно было заботиться о конкретном возвращаемом типе, то это все еще не правильное решение.Окончательное решение (на помощь приходит Opaque Return Type)
func buildPreferredOS() -> some MobileOS {
return iOS(version: 13.1)
}
Используя opaque return type, мы, наконец, можем вернуть MobileOS в качестве типа возврата функции. Здесь компилятор поддерживает идентичность базового конкретного возвращаемого типа, и вызывающей стороне не обязательно знать внутренний тип возвращаемого типа, если он реализует протокол MobileOS.Opaque returns types могут возвращать только один конкретный типВозможно, вы думаете, что как и тип возвращаемого значения протокола, мы также можем возвращать конкретное значение другого типа внутри opaque return type, например.
func buildPreferredOS() -> some MobileOS {
let isEven = Int.random(in: 0...100) % 2 == 0
return isEven ? iOS(version: 13.1) : Android(version: "Pie")
}
// ОШИБКА компилятора
Невозможно преобразовать возвращаемое выражение типа 'iOS'
в возвращаемое выражение типа 'some MobileOS'
func buildPreferredOS() -> some MobileOS {
let isEven = Int.random(in: 0...100) % 2 == 0
return isEven ? iOS(version: 13.1) : iOS(version: "13.0")
}
// Сборка прошла успешно
Компилятор вернет ошибку сборки, если вы пытаетесь вернуть другой конкретный тип для opaque return value. Однако вы все равно можете вернуть другое значение того же конкретного типа.Упрощение сложных и вложенных типов в opaque return type для вызывающего APIПоследний пример opaque return value — действительно хороший пример того, как мы можем использовать Opaque return type, чтобы скрыть сложный и вложенный типы в простой opaque protocol type, который может быть представлен клиенту.Рассмотрим функцию, которая принимает массив, который использует generic constraint для своего элемента, чтобы соответствовать протоколу numeric. Этот массив выполняет несколько функций:
- Отбрасывает элементы головы и хвоста из массива.
- Лениво сопоставьте функцию, выполняя операцию умножения самого себя для каждого элемента.
Вызывающей стороне этого API не нужно знать тип возвращаемого значения функции, вызывающая сторона просто хочет выполнить цикл for и вывести (print) значение последовательности на консоль.Давайте реализуем это с помощью простой функции.Решение 1. Использование Generic Return Function
func sliceFirstAndEndSquareProtocol<T: Numeric>(array: Array<T>) -> LazyMapSequence<ArraySlice<T>, T> {
return array.dropFirst().dropLast().lazy.map { $0 * $0 }
}
sliceFirstAndEndSquareProtocol(array: [2,3,4,5]).forEach { print($0) }
// 9
// 16
Как вы можно увидеть, тип возвращаемого значения этой функции очень сложен и вложен LazyMapSequence, T>, в то время как клиент использует его только для печати каждого элемента в цикле.Решение 2. Простые Opaque Return Types
func sliceHeadTailSquareOpaque<T: Numeric>(array: Array<T>) -> some Sequence {
return array.dropFirst().dropLast().lazy.map { $0 * $0 }
}
sliceHeadTailSquareOpaque(array: [3,6,9]).forEach { print($0) }
// 36
Используя это решение, клиент не нужно знать о базовом возвращаемом типе функции, если он соответствует протоколу sequence, который может использоваться клиентом.Opaque Return Types в SwiftUISwiftUI также в значительной степени зависит от этого подхода, так как body View не обязано демонстрировать конкретный возвращаемый тип до тех пор, пока он соответствует протоколу View. В противном случае предполагаемый тип возвращаемого значения может быть очень сложным и вложенным.
struct Row: View {
var body: some View {
HStack {
Text("Hello SwiftUI")
Image(systemName: "star.fill")
}
}
}
Предполагаемый тип возврата body:
HStack<TupleView<(Text, Image)>>
Он достаточно сложен и вложен, помните, что он также будет меняться всякий раз, когда мы добавляем новое вложенное view внутри HStack. Opaque return type предстает во всей красе в реализации SwiftUI. Пользователя API не сильно заботит базовый конкретный типа в View, покуда возвращаемый тип соответствует протоколу View.Дополнительные сведения о Opaque return typeЧтобы узнать больше о opaque return type, вы можете проследовать по ссылкам, которые я привел ниже. Это официальное предложение, документация и видео от Apple.apple/swift-evolutionЭто предложение является первой частью группы изменений, которые мы рассматриваем в проектном документе для улучшения пользовательского интерфейса…github.comOpaque Types — язык программирования Swift (Swift 5.1)Функция или метод с opaque return type скрывает информацию о типе возвращаемого значения. Вместо предоставления…docs.swift.orgЧто нового в Swift - WWDC 2019 - Видео - Apple DeveloperSwift теперь является главным языком для ряда основных фреймворков на всех платформах Apple, включая…developer.apple.comЗаключениеЭто было очень удивительное и невероятное путешествием для нас, разработчиков Swift, которые изучали и применяли Swift с момента его изначального релиза на WWDC 2014. Если вспомнить его тогда, в этом языке не было ряда удивительных фич, которые открывают новую парадигму построения API, например расширение протокола, генерик в протоколе с associatedtype и даже такие интересные фичи, как протокол Codable для упрощения декодирования и кодирования модели определенного типа данных.Хотя бы только потому, что Apple выпускает Swift в качестве языка программирования с открытым исходным кодом, мы можем использовать силу коллективности разработчиков со всего мира, которые хотят улучшить язык с помощью предложений Swift Evolution. Существует даже реализация предложения, которая была принята в Swift Language от старшеклассника (синтезированный инициализатор по умолчанию для struct в Swift 5.1 от Алехандро Алонсо).Влияние технологии Swift на мир по мере развития языка в будущем может быть очень значительным. Это язык программирования, который мне нравится больше всего из-за его выразительности. Продолжайте учиться и будьте новичком, не бойтесь неудач, извлекайте из них уроки, пробуйте и повторяйте. Продолжайте обучение на протяжении всей жизни и счастливого свифтинга!
Узнать подробнее о курсе «iOS Developer. Professional».
Смотреть открытый вебинар «Пишем приложение на SwiftUI и Combine».
===========
Источник:
habr.com
===========
===========
Автор оригинала: Alfian Losari
===========Похожие новости:
- [Разработка под iOS, Гаджеты, Энергия и элементы питания, Ноутбуки] Apple предложит пользователям заменить аккумуляторы MacBook Pro 2016/2017
- [SQL, Big Data, Визуализация данных, Data Engineering] SQL для аналитики — рейтинг прикладных задач с решениями
- [Программирование, SQL, Go] SQLite с использованием Go и Python (перевод)
- [Разработка под iOS, Swift] Создание пользовательских функций запросов с key paths (перевод)
- [SQLite, Xcode, Swift] Видеомонтаж, машинное обучение и взломанный xml — все в одной программе
- [Разработка под iOS, Компьютерное железо, IT-компании] Apple повысила купон за возврат комплекта разработчика Apple Silicon до $500 и расширила условия его использования
- [Высокая производительность, Разработка под iOS, Разработка мобильных приложений, Разработка под Android, Микросервисы] Envoy как универсальный сетевой примитив
- [Разработка под iOS, IT-компании] Apple попросила разработчиков вернуть DTK с чипом Apple A12Z в обмен на купон в $200. Оборудование они получили за $500
- [Разработка под iOS, Разработка мобильных приложений, Разработка под Android] Чего ждать от коробочных приложений?
- [Разработка под iOS, Разработка мобильных приложений, Разработка под Android, Аналитика мобильных приложений] Как мы просто сократили объем входящего в дата-центр трафика на 70%
Теги для поиска: #_razrabotka_pod_ios (Разработка под iOS), #_swift, #_swiftui, #_swift, #_combine, #_ios, #_ios_app_development, #_swift__razrabotka (swift разработка), #_blog_kompanii_otus._onlajnobrazovanie (
Блог компании OTUS. Онлайн-образование
), #_razrabotka_pod_ios (
Разработка под iOS
), #_swift
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 12:07
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Привет, Хабр. В рамках стартующего в феврале курса «iOS Developer. Professional»подготовили для вас перевод полезного материала.
Также предлагаем принять участие в открытом вебинаре на тему «Пишем приложение на SwiftUI и Combine». Участники вместе с экспертом разберут, что такое SwiftUI и фреймворк Combine, а также как с их помощью создать небольшое приложение. Вы также можете прочитать эту статью в моем блоге Xcoding With Alfian, перейдя по ссылке.Opaque return types (непрозрачные типы) — это новая языковая конструкция, представленная Apple в Swift 5.1. Их можно использовать для возврата некоторого (some) значения функции (function)/метода (method) и свойства (property), не раскрывая конкретный тип значения клиенту, который вызывает API. Тип возврата будет некоторым типом, реализующим протокол (protocol). С помощью этого решения API-интерфейс модуля больше не должен публично раскрывать базовый внутренний возвращаемый тип метода, ему просто нужно вернуть opaque type протокола с помощью ключевого слова some. Компилятор Swift также сможет сохранить базовую идентичность (identity) возвращаемого типа, в отличии от варианта с использованием протокола в качестве возвращаемого типа. SwiftUI использует opaque return typesвнутри своего протокола View, который возвращает some View в свойстве body.Вот некоторые из важных возможностей, предоставляемых opaque return types, которые закрепят их в нашем наборе инструментов и будут использоваться всякий раз, когда мы захотим создать API с использованием Swift:
protocol MobileOS {
associatedtype Version var version: Version { get } init(version: Version) } struct iOS: MobileOS {
var version: Float } struct Android: MobileOS { var version: String } func buildPreferredOS() -> MobileOS {
return iOS(version: 13.1) } // ОШИБКА компилятора Протокол 'MobileOS' может использоваться только как общее ограничение, потому что у него есть требования к типу Self или associated type. func buildPreferredOS() -> iOS {
return iOS(version: 13.1) } // Сборка прошла успешно func buildPreferredOS<T: MobileOS>(version: T.Version) -> T {
return T(version: version) } let android: Android = buildPreferredOS(version: "Jelly Bean") let ios: iOS = buildPreferredOS(version: 5.0) func buildPreferredOS() -> some MobileOS {
return iOS(version: 13.1) } func buildPreferredOS() -> some MobileOS {
let isEven = Int.random(in: 0...100) % 2 == 0 return isEven ? iOS(version: 13.1) : Android(version: "Pie") } // ОШИБКА компилятора Невозможно преобразовать возвращаемое выражение типа 'iOS' в возвращаемое выражение типа 'some MobileOS' func buildPreferredOS() -> some MobileOS { let isEven = Int.random(in: 0...100) % 2 == 0 return isEven ? iOS(version: 13.1) : iOS(version: "13.0") } // Сборка прошла успешно
func sliceFirstAndEndSquareProtocol<T: Numeric>(array: Array<T>) -> LazyMapSequence<ArraySlice<T>, T> {
return array.dropFirst().dropLast().lazy.map { $0 * $0 } } sliceFirstAndEndSquareProtocol(array: [2,3,4,5]).forEach { print($0) } // 9 // 16 func sliceHeadTailSquareOpaque<T: Numeric>(array: Array<T>) -> some Sequence {
return array.dropFirst().dropLast().lazy.map { $0 * $0 } } sliceHeadTailSquareOpaque(array: [3,6,9]).forEach { print($0) } // 36 struct Row: View {
var body: some View { HStack { Text("Hello SwiftUI") Image(systemName: "star.fill") } } } HStack<TupleView<(Text, Image)>>
Узнать подробнее о курсе «iOS Developer. Professional».
Смотреть открытый вебинар «Пишем приложение на SwiftUI и Combine». =========== Источник: habr.com =========== =========== Автор оригинала: Alfian Losari ===========Похожие новости:
Блог компании OTUS. Онлайн-образование ), #_razrabotka_pod_ios ( Разработка под iOS ), #_swift |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 12:07
Часовой пояс: UTC + 5