Swift 6 — это важное обновление языка программирования Swift, разработанного Apple. Данная версия включает множество нововведений и улучшений, особенно в области параллелизма. В этом документе мы рассмотрим основные изменения и их влияние на разработчиков, опираясь на официальную документацию Apple.
Пожалуйста, обратите внимание, что все упомянутые изменения являются актуальными на момент выхода Swift 6, и в будущем могут появиться новые обновления и дополнения. Рассмотрим основные нововведения Swift 6, начиная с изменений в доменах изоляции и параллелизма.
Полный параллелизм включен по умолчанию
Swift 6 включает в себя множество обновлений, касающихся параллелизма, и команда разработчиков может гордиться своими достижениями. Самое значительное изменение заключается в том, что полная проверка параллельности теперь включена по умолчанию. Это изменение может потребовать некоторых корректировок в вашем коде, что неудивительно, так как в предыдущих версиях эта функция была опциональной, чтобы дать разработчикам время адаптироваться к изменениям.
Swift 6 улучшает проверку параллелизма, устраняя множество ложных предупреждений о гонках данных, которые присутствовали в версии 5.10. Внесены также ряд целевых изменений, которые делают параллелизм легче для освоения.
Одним из крупнейших нововведений является SE-0414, который вводит домены изоляции, позволяющие компилятору убедительно доказать, что различные части вашего кода могут выполняться параллельно.
В основе этого изменения лежит существующая концепция отправляемости (sendability). Тип Sendable — это такой тип, который можно безопасно передавать в параллельной среде. Это могут быть типы значений, такие как структуры, финальные классы с константными свойствами, акторы, которые автоматически защищают свое изменяемое состояние, и многое другое.
Ранее компилятор Swift был очень строг: если у вас было значение, не поддающееся отправке (non-sendable), и вы пытались передать его другому актору, вы получали предупреждение о проверке параллельности. Например, хотя тела представлений SwiftUI выполняются на основном акторе, сами представления SwiftUI этого не делают, что может легко вызвать ложные предупреждения компилятора.
Рассмотрим следующий код:
class User { var name = "Anonymous" } struct ContentView: View { var body: some View { Text("Hello, world!") .task { let user = User() await loadData(for: user) } } func loadData(for user: User) async { print("Loading data for \(user.name)…") } }
До Swift 6 вызов функции loadData() вызвал бы предупреждение: «передача аргумента типа ‘User’ за пределы изолированного контекста основного актора может вызвать гонки данных.»
В Swift 6 это предупреждение исчезает: Swift теперь определяет, что код не представляет проблемы, так как user не используется одновременно из нескольких мест, и не выдаст предупреждение. Компилятор анализирует поток программы и определяет, что это безопасно.
Это изменение означает, что объекты, пригодные для отправки, теперь либо соответствуют протоколу Sendable, либо не нуждаются в этом, потому что компилятор может доказать, что они используются безопасно — это значительное улучшение параллелизма для разработчиков, возможно благодаря передовым разработкам компилятора.
Также внесены множество других, более мелких улучшений, включая:
-
SE-430 добавляет новое ключевое слово sending, когда нужно отправить значения между доменами изоляции.
-
SE-0423 улучшает поддержку параллельности при работе с фреймворками Objective-C.
-
SE-0420 позволяет создавать асинхронные функции, изолированные тем же актором, что и их вызывающий код.
Устаревшие функции
Некоторые изменения были доступны в предыдущих версиях Swift, но скрыты за флажками функций. Например, SE-0401 удаляет функцию, введенную в Swift 5.5: вывод акторов для оберток свойств.
Ранее любой структурный или классовый тип, использующий обертку свойства с @MainActor для его обернутого значения, автоматически становился @MainActor. Это позволило @StateObject и @ObservedObject передавать «main-actor-ness» на представления SwiftUI, которые их используют.
@MainActor class ViewModel: ObservableObject { func authenticate() { print("Authenticating…") } } @MainActor struct LogInView: View { @StateObject private var model = ViewModel() var body: some View { Button("Hello, world", action: startAuthentication) } func startAuthentication() { model.authenticate() } }
Ранее @MainActor присваивался бы всему представлению из-за его свойства @StateObject.
Строгий параллелизм для глобальных переменных
Еще одно старое изменение, теперь включенное в Swift 6, — SE-0412, требующее, чтобы глобальные переменные были безопасны в параллельных средах. Это касается как глобальных переменных в проекте, так и статических переменных в типах.
Примеры:
var gigawatts = 1.21 struct House { static var motto = "Winter is coming" }
Эти данные могут быть доступны в любое время, что делает их небезопасными. Чтобы решить эту проблему, нужно либо преобразовать переменную в sendable-константу, либо ограничить ее глобальным актором, например, @MainActor, либо, если нет других вариантов, пометить её как nonisolated.
struct XWing { @MainActor static var sFoilsAttackPosition = true } struct WarpDrive { static let maximumSpeed = 9.975 } @MainActor var idNumber = 24601 // Не рекомендуется, если вы не уверены, что это безопасно nonisolated(unsafe) var britishCandy = ["Kit Kat", "Mars Bar", "Skittles", "Starburst", "Twix"]
Изменения в значениях по умолчанию для функций
Другое изменение, которое теперь включено, — SE-0411, которое изменяет значения по умолчанию для функций так, чтобы они имели ту же изоляцию, что и сама функция.
@MainActor class Logger {} @MainActor class DataController { init(logger: Logger = Logger()) {} }
Поскольку и DataController, и Logger ограничены основным актором, Swift теперь считает создание Logger() также ограниченным основным актором, что имеет смысл.
Новый метод count(where:)
SE-0220 ввел новый метод count(where:), который выполняет эквивалент filter() и count в одном проходе. Это экономит создание нового массива, который сразу же отбрасывается, и предоставляет ясное и лаконичное решение распространенной проблемы.
Пример:
let scores = [100, 80, 85] let passCount = scores.count { $0 >= 85 }
Этот метод доступен для всех типов, которые соответствуют Sequence, так что вы можете использовать его для множеств и словарей.
Типизированные выбросы ошибок (Typed Throws)
SE-0413 ввел возможность указать, какие именно типы ошибок может выбросить функция, известную как «typed throws». Это решает неудобство с ошибками в Swift: раньше требовалось общее выражение catch, даже если вы специально обрабатывали все возможные ошибки.
Пример:
enum CopierError: Error { case outOfPaper } struct Photocopier { var pagesRemaining: Int mutating func copy(count: Int) throws(CopierError) { guard count <= pagesRemaining else { throw CopierError.outOfPaper } pagesRemaining -= count } } do { var copier = Photocopier(pagesRemaining: 100) try copier.copy(count: 10) } catch CopierError.outOfPaper { print("Please refill the paper") }
Итерация пакета (Pack Iteration)
SE-0408 вводит итерацию по пакетам, что добавляет возможность обхода параметров пакета, введенных в Swift 5.9. Это позволяет, например, сравнивать кортежи любой арности всего в нескольких строках кода:
func == <each Element: Equatable>(lhs: (repeat each Element), rhs: (repeat each Element)) -> Bool { for (left, right) in repeat (each lhs, each rhs) { guard left == right else { return false } } return true }
Операции с элементами коллекций
SE-0270 вводит различные новые методы для работы с коллекциями, такие как перемещение или удаление нескольких элементов, которые не являются смежными. Это изменение поддерживается новым типом RangeSet.
Пример:
struct ExamResult { var student: String var score: Int } let results = [ ExamResult(student: "Eric Effiong", score: 95), ExamResult(student: "Maeve Wiley", score: 70), ExamResult(student: "Otis Milburn", score: 100) ] let topResults = results.indices { student in student.score >= 85 } for result in results[topResults] { print("\(result.student) scored \(result.score)%") }
Модификаторы уровня доступа для объявлений импорта
SE-0409 добавляет возможность отмечать объявления импорта модификаторами уровня доступа, такими как private import SomeLibrary. Это помогает разработчикам библиотек избегать случайного утечки собственных зависимостей.
Пример:
// Внутренняя библиотека public struct BankTransaction { // код здесь } // Основная библиотека public func sendMoney(from: Int, to: Int) -> BankTransaction { // обработка перевода денег return BankTransaction() } // Основное приложение import BankingLibrary sendMoney(from: 123, to: 456)
С Swift 6 можно использовать internal import Transactions в основной библиотеке, чтобы ограничить видимость.
Улучшения для noncopyable типов
Несколько улучшений для noncopyable типов, введенных в Swift 5.9. Noncopyable типы позволяют создавать типы с уникальным владением, которые можно передавать, используя заимствование или потребление.
Пример:
struct Message: ~Copyable { var agent: String private var message: String init(agent: String, message: String) { self.agent = agent self.message = message } consuming func read() { print("\(agent): \(message)") } } func createMessage() { let message = Message(agent: "Ethan Hunt", message: "You need to abseil down a skyscraper for some reason.") message.read() } createMessage()
В Swift 6, все структуры, классы, перечисления, параметры обобщений и протоколы автоматически соответствуют новому протоколу Copyable, если явно не отказаться от него, используя ~Copyable.
Типы 128-битных целых чисел
SE-0425 вводит Int128 и UInt128. Эти типы работают так же, как и другие целочисленные типы в Swift.
Пример:
let enoughForAnybody: Int128 = 170_141_183_460_469_231_731_687_303_715_884_105_727
Протокол BitwiseCopyable
SE-0426 вводит новый протокол BitwiseCopyable, который позволяет компилятору создавать более оптимизированный код для соответствующих типов.
Пример:
@frozen public enum CommandLine: ~BitwiseCopyable { }
Эти улучшения помогают делать noncopyable типы более естественными в использовании и повышают производительность кода.
Swift 6 приносит значительные улучшения, особенно в доменах параллелизма, делая ее более доступной и понятной для разработчиков. Новые возможности, такие как полная проверка параллелизма по умолчанию, домены изоляции и усовершенствованное понятие sendability, упрощают написание безопасного и эффективного кода. Большая часть изменений направлена на адаптацию разработчиков к новым требованиям и использованию мощных функций языка Swift для создания высокопроизводительных приложений.
Полагаю что это только начало, начало огромного будущего нами всеми любимого языка.
ссылка на оригинал статьи https://habr.com/ru/articles/820961/
Добавить комментарий