Краткое описание новых функций Swift 5.6–5.10
Краткое описание новых функций Swift 5.6–5.10

Intro

Swift 5.10

Глобальные переменные строго конкурируют.

SE-0412 дальнейшее укрепление Swift Возможность предотвращения гонок данных во время компиляции.

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

В Swift 5.10 компилятор позволяет вам получить доступ к общему изменяемому состоянию из параллельного контекста только при следующих обстоятельствах:

  • этотиндивидуальныйсостояниеданеизменныйизисоответствовать Sendable(существоватьэтотвнутри Понятноразвязать Болеео Sendable информация)
  • Этот индивидуальный статус изолирован от индивидуальной общающейся ситуация actor(нравиться @MainActor или Напишите самииз actor)
Язык кода:javascript
копировать
var mutableGlobal = 1
// warning: var 'mutableGlobal' is not concurrency-safe because it is non-isolated global shared mutable state
// (unless it is top-level code which implicitly isolates to @MainActor)

final class NonsendableType {
  init() {}
}

struct S {
  static let immutableNonsendable = NonsendableType()
  // warning: static property 'immutableNonsendable' is not concurrency-safe because it is not either conforming to 'Sendable' or isolated to a global actor
}

В любом другом случае компилятор посчитает одновременный доступ к общему состоянию небезопасным.

Если вы предпримете шаги, чтобы избежать Swift одновременно actor и Sendability(Например,потому чтодлятысуществоватьиметь дело сиспользовать Семафор или DispatchQueue Чтобы синхронизировать доступ к устаревшему коду, вы можете сделать это, изменив общую Тег переменной ситуации для nonisolated(unsafe) чтобы отказаться от проверки параллелизма на них. Этот тег сообщит компилятору, что он не требует каких-либо проверок безопасности помеченных свойств. Вы убедились, что код можно безопасно использовать в параллельном контексте;

Язык кода:javascript
копировать
nonisolated(unsafe) var global: String

Волясвойствоотметкадля nonisolated(unsafe) Подобно принудительной распаковке файла, вы можете быть уверены, что ваш код безопасен. будет работать как положено Работа,Но ты сам по себе. ты сказал компилятору,Ты знаешь, что ты существуешь,Вам не нужен компилятор для выполнения каких-либо проверок.

Всякий раз, когда вы хотите использовать nonisolated(unsafe) , вам следует спросить себя, можете ли вы на самом деле изолировать отмеченный вами тип в глобальном actor,или можете ли вы сделатьсвойствоизтип Sendable И неизменяемый.

Устарело @UIApplicationMain и @NSApplicationMain

SE-0383 @UIApplicationMain и @NSApplicationMain были когда-то iOS и macOS Стандартный способ объявления приложений синтетических точек входа для конкретных платформ. с Swift 5.3 представлять @main После атрибута эти функции устарели.

Эта версия будет в Swift 6 Раньше Устарело эти атрибуты точки входа заменялись, вместо этого использовали @main,иисуществовать Swift 6 Их использование приведет к ошибкам.

Язык кода:javascript
копировать
@UIApplicationMain // warning: '@UIApplicationMain' is deprecated in Swift 5 
                   // fixit: Change `@UIApplicationMain` to `@main` 
final class MyApplication: UIResponder, UIApplicationDelegate {
  /**/
}

Следует использовать:

Язык кода:javascript
копировать
@main
final class MyApplication: UIResponder, UIApplicationDelegate {
  /**/
}

Разрешить вложение протоколов в неуниверсальных контекстах

Допротоколвообще не может быть вложенным,таквсегда должендав модулеиз Вершинатип.SE-0404 Swift 5.10 Это ограничение будет смягчено.

Например,TableView.Delegate Естественно, это связано с представлением таблицы из протокола делегата. Вы должны объявить это вот так - вложенный в их TableView В категории:

Язык кода:javascript
копировать
class TableView {
  protocol Delegate: AnyObject {
    func tableView(_: TableView, didSelectRowAtIndex: Int)
  }
}

class DelegateConformer: TableView.Delegate {
  func tableView(_: TableView, didSelectRowAtIndex: Int) {
    // ...
  }
}

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

Изолированное выражение значения по умолчанию

SE-0411: Выражения значений по умолчанию теперь могут иметь ту же изоляцию, что и включающая функция или соответствующее сохраненное свойство Isolate:

Язык кода:javascript
копировать
@MainActor
func requiresMainActor() -> Int { ... }

class C {
  @MainActor
  var x: Int = requiresMainActor()
}

@MainActor func defaultArg(value: Int = requiresMainActor()) { ... }

Для изолированных значений по умолчанию хранимых свойств неявная инициализация происходит только в телах инициализации с такой же изоляцией. Это закрывает важную уязвимость безопасности в гонке данных, из-за которой значение по умолчанию для глобальной изоляции субъекта может непреднамеренно выполняться синхронно извне субъекта.

Данное предложение в основном решает следующие проблемы:

  • существовать в контексте параллелизма,Выражение значения по умолчанию из изолировать не соответствует принадлежащему ему свойству изфункцииили.,Может привести к конкуренции данных.
  • общая ситуация actor Изоляция значений по умолчанию может неожиданно actor Операция внешней синхронизации, нарушение actor Изоляция из принципа.

проходитьпредставлять Изолированное выражение значения по умолчанию,Предложение обеспечивает более безопасный и последовательный способ обработки значений по умолчанию в параллельных средах.,Уменьшает потенциальные ошибки параллелизма,Улучшена читаемость и ремонтопригодность кода.

Более:function parameter isolate

о Актер и инициализация

SE-0327 предназначен для укрепления actor определение, ясно actor Примеры изданные Когда начинается и заканчивается карантин, и существует ли он actor из init и deinit Объявляет, что можно сделать в основном теле.

actor или глобальный actor Изолированный тип (GAIT) из Неделегированного инициализатора необходим для инициализации всех свойств хранения в этом типе.

Хотя actor да Цитироватьтип,Но они из инициализаторов делегатов будут следовать тем же основным правилам, что и тип значения.,Прямо сейчас:

  • Если тело инициализатора содержит паруопределенныйиндивидуальный self.init из, то это инициализатор делегата. Нет необходимости использовать convenience Ключевые слова.
  • Для инициализаторов делегатов существованиеиспользовать self Прежде существование должно быть призвано на всех путях self.init

actor и class Причины такого различия между типизда actor основания не наследуются, поэтому они могут избавиться от сложности делегатов инициализатора класса. ПОХОДКА use использует ту же синтаксическую форму, что и обычный класс, для определения инициализатора делегата.

init и deinit Единственная разница между изда, деинит Доступен только Sendable атрибут, в то время как init Может получить доступ к не- Sendable свойство.

Основное содержание включает в себя:

  1. Actor из Неделегирующий инициализатор Initializers):
    • Actor из Неделегированный инициализатор должен инициализировать Actor из всего магазинасвойство.
    • Это гарантирует Actor существуют После завершения инициализации Все свойства были правильно инициализированы.,Избегайте одновременного доступа к неинициализированному изсвою.
  2. Actor из Делегирующий инициализатор (Делегирование Initializers):
    • Хотя актер ссылается на тип, но его инициализатор делегата следует тем же правилам, что и тип значения.
    • Если тело инициализатора содержит пару self.init из вызова, то это индивидуальный инициализатор делегата, использовать его не нужно. convenience Ключевые слова.
    • Для инициализаторов делегатов,Self.init должен вызываться на всех путях,Затемталантиспользовать self。
  3. общая ситуация Actor Тип изоляции (Global-Actor) Isolated Types, GAIT):
    • GAIT из правил инициализатора с Actor такой же.
    • GAIT use использует ту же синтаксическую форму, что и обычный класс, для определения инициализатора делегата.
  4. Actor из deinit:
    • Actor из deinit Доступен только Sendable атрибут, в то время как init Может получить доступ к не- Sendable свойство.

Это индивидуальное предложение из цели принято четко Actor Инициализатор строки для правил, чтобы гарантировать Actor существуют из правильности и безопасности в параллельной среде. Это для Actor Процесс инициализации предоставляет четкие рекомендации, которые помогут разработчикам писать более устойчивые, надежные и параллельные приложения.

пройти спецификацию Actor Инициализатор семантики и ограничений, предложение направлено на улучшение Swift Модель параллелизма, обеспечивающая согласованность и предсказуемость, улучшает использование разработчиками. Actor из Опыта и Эффективности.

Swift 5.9

if иswitchвыражение

SE-0380 разрешено в Swift генерал-лейтенант if и switch Используемый в качестве выражения, он уменьшает количество шаблонов в вашем коде.

Основные преимущества:

  • **Проще из кода:** Больше нет необходимости в существовании. if и switch в предложениииспользовать return Ключевые слова.
  • Более выразительно:if и switch выражение Может Вложенныйсуществоватьдругойвыражениесередина,оти добиться большей гибкостиизкодструктура。
Язык кода:javascript
копировать
// существовать Swift 5.1 До
func rating(for score: Int) -> String {
    if score > 500 {
        return "Pass"
    } else {
        return "Fail"
    }
}

// существовать Swift 5.1 и более поздние версии
func rating(for score: Int) -> String {
    score > 500 ? "Pass" : "Fail"
}

Что следует отметить:

  • if и switch Различные ветви выражения должны иметь один и тот же изтип.
  • if Условие в выражении должно быть логическим значением.

Пакеты параметров значений и типов

пакет параметровпозволятьтыписатьиметь дело слюбое числотипиз Дженерикитипифункция。

Например, если нет пакета параметры, если вы хотите написать имя для all функция проверки любого числа из Optional ценитьданетдля nil,Вам нужно для каждого отдельного человека, и вы хотите, чтобы длина параметра подтверждения прописывалась отдельно для каждого отдельного человека из-за перегрузки.,от при создании индивидуального произвольного из шапки:

Язык кода:javascript
копировать
func all<W1>(_ optional: W1?) -> W1?
func all<W1, W2>(_ optional1: W1?, optional2: W2?) -> (W1, W2)?
func all<W1, W2, W3>(_ optional1: W1?, optional2: W2?, optional3: W3?) -> (W1, W2, W3)?

Используя пакеты параметров, вы можете использовать это API выражатьдляодининдивидуальныйнет верхнего пределаизодининдивидуальныйфункция,позволять Вы передаете любое числоизпараметр:

Язык кода:javascript
копировать
func all<each Wrapped>(_ optional: repeat (each Wrapped)?) -> (repeat each Wrapped)?

Вызов API параметров использования пакета интуитивно понятен и не требует дополнительных действий:

Язык кода:javascript
копировать
if let (int, double, string, bool) = all(optionalInt, optionalDouble, optionalString, optionalBool) {
  print(int, double, string, bool)
}
else {
  print("got a nil")
}

Метод многопараметрической записи также поддерживается:

Язык кода:javascript
копировать
func pairUp3<each T: WritesFrontEndCode, each U: WritesBackEndCode>(firstPeople: repeat each T, secondPeople: repeat each U) -> (repeat (first: each T, second: each U)) {
    return (repeat (each firstPeople, each secondPeople))
}

Макрос

SE-0382, SE-0389, SE-0397 для Swift Привез Макрос. Макросда Мощный инструмент, позволяющий создавать существующие исходные коды преобразования во время компиляции.

Ключевые выводы:

  • МакросдатипSafetyиз, нужно точно знать, какие они будут использовать Чтоданные。
  • Они запускаются на этапе сборки внешних программ.
  • Макрос имеет различный тип, в том числе для генерации выражений из ExpressionMacro ииспользуется длядобавить в getter и setter из AccessorMacro,ConformanceMacro используется дляделатьтипсоответствоватьпротокол。
  • Макрос вместе с вашим исходным кодом. Работайте, улучшая ваш запрос и код операции из каждой отдельной части.
  • Они существуют в песочнице Работа, может работать только изданные.
  • Swift из Макросподдержки вокруг Apple из SwiftSyntax Сборка библиотеки для понимания и работы с исходным кодом. Вы должны сделать это зависимостью для Макросиздобавить. в

использовать Макросизшаг:

  1. Создайте индивидуальное исполнение Макроса для расширения исходника.
  2. существоватьодининдивидуальныйодинодинизв модулесоздаватьодининдивидуальныйсоответствовать CompilerPlugin протоколизструктура,Экспортируйте вас из Макрос.
  3. существоватьтыиз Package.swift в файледобавить в Макросмодуль。
  4. Существование Макроса заявлено в качестве вашей главной цели.
  5. использовать Макрос。

использовать Макрос:

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

Но и:

  • Макросы могут быть сложными и трудными для отладки.
  • они могутделатькод更难理развязатьиподдерживать。

Например Во-первых, нам нужно создать код, который выполняет расширение Макроса из - put #buildDate стать похожим на 2023-06-05T18:00:00Z из вещей:

Язык кода:javascript
копировать
public struct BuildDateMacro: ExpressionMacro {
    public static func expansion(
        of node: some FreestandingMacroExpansionSyntax,
        in context: some MacroExpansionContext
    ) -> ExprSyntax {
        let date = ISO8601DateFormatter().string(from: .now)
        return "\"\(raw: date)\""
    }
}

ВАЖНОЕ ПРИМЕЧАНИЕ: Этот код не должен находиться в цели вашего основного приложения; мы не хотим, чтобы этот код был скомпилирован в наше окончательное приложение, мы просто хотим, чтобы он содержал окончательную строку даты. В этом же модуле мы создаем CompilerPlugin протоколизструктура,Экспортируйте нас из Макрос:

Язык кода:javascript
копировать
import SwiftCompilerPlugin
import SwiftSyntaxMacros

@main
struct MyMacrosPlugin: CompilerPlugin {
    let providingMacros: [Macro.Type] = [
        BuildDateMacro.self
    ]
}

Затем,нас Воля Чтодобавить в прибыть Package.swift В списке целей:

Язык кода:javascript
копировать
.macro(
  name: "MyMacrosPlugin",
  dependencies: [
    .product(name: "SwiftSyntax", package: "swift-syntax"),
    .product(name: "SwiftSyntaxMacros", package: "swift-syntax"),
    .product(name: "SwiftCompilerPlugin", package: "swift-syntax")
  ]
),

На этом создание Макроса во внешнем модуле завершено. Остальная часть нашего кода используется везде, где мы хотим использовать Макросимерсуществовать в пределах нашей основной цели приложения. Для этого необходимо сделать два шага: сначала определить, что такое Макросда. В нашем примере этот даиндивидуальный вернет отдельную строку из автономного выражения Макрос, которая хранится в существовании. MyMacrosPlugin модуль и имеет строгое имя BuildDateMacro。поэтому,нас Воляэто определениедобавить в прибытьнасизглавная цель:

Язык кода:javascript
копировать
@freestanding(expression)
macro buildDate() -> String =
  #externalMacro(module: "MyMacrosPlugin", type: "BuildDateMacro")

Второй шаг индивидуального даактуального использования Макроса заключается в следующем:

Язык кода:javascript
копировать
print(#buildDate)

Когда вы читаете этот код,Самый важный урожайда,основнойиз Макрос Функция——BuildDateMacro Весь код в структуре - существования запускается во время сборки, и его результаты внедряются на сайт вызова. Поэтому выше мы print() Вызов будет переписан примерно так:

Язык кода:javascript
копировать
print("2023-06-05T18:00:00Z")

Снова Например,Попробуйте индивидуальный более полезный из Макрос,На этот раз я сделал индивидуальный атрибут участника Макрос. Применительно к типу (классу – например),этотпозволятьнасвернодобрыйсерединаиз Каждыйиндивидуальный Заявление участникаодининдивидуальныйсвойство.этотистаршеиз @objcMembers Атрибут существование концептуально аналогичен даиз. @objc добавить в прибытьтипсерединаиз Каждыйиндивидуальныйсвойство. Например,еслитыиметьодининдивидуальныйиспользовать @Published Каждое индивидуальное свойство существования наблюдаемого объекта можно написать простое индивидуальное из @AllPublished Макросприходите, чтобы закончить эту Работу. Сначала напишем сам Макрос:

Язык кода:javascript
копировать
public struct AllPublishedMacro: MemberAttributeMacro {
    public static func expansion(
        of node: AttributeSyntax,
        attachedTo declaration: some DeclGroupSyntax,
        providingAttributesFor member: some DeclSyntaxProtocol,
        in context: some MacroExpansionContext
    ) throws -> [AttributeSyntax] {
        [AttributeSyntax(attributeName: SimpleTypeIdentifierSyntax(name: .identifier("Published")))]
    }
}

Во-вторых, включите его в список существующих ваших поставщиков:

Язык кода:javascript
копировать
struct MyMacrosPlugin: CompilerPlugin {
    let providingMacros: [Macro.Type] = [
        BuildDateMacro.self,
        AllPublishedMacro.self,
    ]
}

третий,существованиевы из основной цели приложения заявил Макрос,этот Второсортный Воля Чтоотметкадлядополнительные членысвойство Макрос:

Язык кода:javascript
копировать
@attached(memberAttribute)
macro AllPublished() = #externalMacro(module: "MyMacrosPlugin", type: "AllPublishedMacro")

Теперь существуетиспользовать его, чтобы аннотировать ваш наблюдаемый класс объектов:

Язык кода:javascript
копировать
@AllPublished class User: ObservableObject {
    var username = "Taylor"
    var age = 26
}

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

Swift член командыподдерживать ПонятноодининдивидуальныйГитхаб, есть некоторые macro из Пример

Некопируемая структура struct и перечисление enum

SE-0390 представлять Потрясающийкопироватьизструктурателои перечисление。Напротив, оно можеткопироватьизструктурателои перечислениеизодининдивидуальный Экземпляры могутсуществоватьмногоиндивидуальныйобмен местами——Хотясуществоватькодкаждыйиндивидуальныйместный визит,Но в итоге владелец все равно один.

первый,этотвнутрипредставлять Понятноодининдивидуальныйновый синтаксис:~Copyable。этотиндивидуальныйграмматикадаодинтелоиз,Других на данный момент нетиз~Equatableкартинаизграмматика。

поэтомунассоздаватьодининдивидуальный НеткопироватьUserструктуратело:

Язык кода:javascript
копировать
struct User: ~Copyable {
    var name: String
}

Уведомление:Неткопироватьтип,Нетспособный СноваследоватьSendableснаружиизпротокол。

Как только мы заявим, что для не копировать,Хорошо, все будет иначе, чем раньше,Например, ниже

Язык кода:javascript
копировать
func createUser() {
    let newUser = User(name: "Anonymous")

    var userCopy = newUser
    print(userCopy.name)
}

createUser()

Вроде бы нет никакой разницы между вышеописанными методами, но мы имеем User Объявление структуры для невозможно скопировать - как это можно скопировать newUser Что? Ответ: не может: будет? newUser назначен на userCopy приведет к оригинальному из newUser Значение потребляется (consume), а это означает, что оно больше не может быть использовано, поскольку для владения теперь принадлежит существующему. userCopy。еслитыпытаться Воля print(userCopy.name) Изменить для print(newUser.name),тыбуду читатьприезжать Swift выдать ошибку компилятора - этотда Нетпозволятьиз。

После использования экземпляра ~Copyable при вызове исходного значения сообщается об ошибке.
После использования экземпляра ~Copyable при вызове исходного значения сообщается об ошибке.

SE-0377 Также имеются новые ограничения при преобразовании копироватьтип для параметров функции:

  • Если вы готовы потреблять этикетки consuming。иметь в видуфункция После звонка,Исходное значение будет недействительным.
  • или Отмеченодля borrowing,и Другие заемщики читают стоимость вместе,следующее.
Язык кода:javascript
копировать
func createAndGreetUser() {
    let newUser = User(name: "Anonymous")
    greet(newUser)
    print("Goodbye, \(newUser.name)")
}

func greet(_ user: borrowing User) {
    print("Hello, \(user.name)!")
}

createAndGreetUser()

если мы позволим greet() Использование функции consuming User,но Нетпозволять print("Goodbye, (newUser.name)") - Swift узнаетдлясуществовать greet() После запуска newUser ценитьневерный。Другойодинаспект,Из-за метода для потребления должен завершиться жизненный цикл объекта.,Таким образом, они могут свободно менять свою собственность.

потребление не может копироватьиспользовать ошибку после экземпляра
потребление не может копироватьиспользовать ошибку после экземпляра

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

Важное примечание: Это немного отличается от деструктора класса, что может быть незначительной проблемой в ранних реализациях.

первый,Этот класс можно использовать из деструктора из кода:

Язык кода:javascript
копировать
class Movie {
    var name: String

    init(name: String) {
        self.name = name
    }

    deinit {
        print("\(name) is no longer available")
    }
}

func watchMovie() {
    let movie = Movie(name: "The Hunt for Red October")
    print("Watching \(movie.name)")
}

watchMovie()

Когда он запускается, он печатает «Наблюдение The Hunt for Red Октябрь», затем напечатайте «The Hunt for Red October is no longer доступен». Но если определить типизот class Movie Изменить для struct Movie: ~Copyable,тыбуду читатьприезжатьэтотдваиндивидуальный print() Операторы выполняются в обратном порядке.

Недоступно в рамках копировать типизметод по умолчанию дазаимствованныйиз,ноэтоих Можеткартина Можеткопироватьтиподин Образецотметкадляmutatingпеременнаяиз,И они также могут быть помечены как расходные материалы.,выражать Долженценитьсуществоватьметод После запусканеверный。

Язык кода:javascript
копировать
struct MissionImpossibleMessage: ~Copyable {
    private var message: String

    init(message: String) {
        self.message = message
    }

    consuming func read() {
        print(message)
    }
}

Это помечает само сообщение как личное, поэтому его можно использовать только путем вызова экземпляра из read() способ посетить его.

В отличие от переменного метода,расходный материалметод МожетсуществоватьтипизпостоянныйletЗапуск на экземпляре。поэтому,такизкодда Можетиз:

Язык кода:javascript
копировать
func createMessage() {
    let message = MissionImpossibleMessage(message: "You need to abseil down a skyscraper for some reason.")
    message.read()
}

createMessage()

Уведомление: потому чтодля message.read() Экземпляр сообщения использован, поэтому попробуйте позвонить еще раз. message.read() даошибкаиз。

В сочетании с деструкторомиспользуйте,Расходный метод станет сложнее,Потому что они могут повторить любую уборку, которую вы делаете. Например,Если вы существуете, следите за рекордами в игре,ты Можетспособный希望иметьодининдивидуальныйрасходный материализ finalize() метод,Запишите последний рекорд в постоянное хранилище и не позволяйте другим в дальнейшем изменять этот результат.,Но у вас также может быть деструктор,Сохраните последний результат на диск, когда объект будет уничтожен.

для Чтобы избежать этой индивидуальной проблемы, Swift 5.9 представлять Понятноодининдивидуальныйновыйиз discard Оператор, который можно использовать для потребляемого метода, который не является копиртипизацией. Когда вы существуете, расходный методсерединаиспользовать discard self , это не позволяет запустить деструктор для этого объекта.

поэтому,нас Можеттак Реальностьсейчаснасиз HighScore Структура:

Язык кода:javascript
копировать
struct HighScore: ~Copyable {
    var value = 0

    consuming func finalize() {
        print("Saving score to disk…")
        discard self
    }

    deinit {
        print("Deinit is saving score to disk…")
    }
}

func createHighScore() {
    var highScore = HighScore()
    highScore.value = 20
    highScore.finalize()
}

createHighScore()

Совет: Когда этот код запустится, вы увидите сообщение деструктора, напечатанное дважды. - однажды, когда мы меняемся value свойство, это фактически уничтожает и воссоздает структуру, а в другой раз, когда createHighScore() В конце метода.

существоватьиспользовать Когда дело доходит до новых функций, необходимо учитывать некоторые дополнительные сложности:

  1. категория actor невозможно скопировать.
  2. В настоящее время нет универсального утверждения, в этой строке кроме необязательных некопировать объекты, а также не копировать объекты из массивов.
  3. еслитысуществовать Другойодининдивидуальныйструктурателоили перечислениесерединаиспользовать Неткопироватьтипделатьдлясвойство,тогда отецструктурателоили перечислениетакже долженда Неткопироватьиз。
  4. Вам нужно быть очень осторожным с существующим типом в добавлении вили Удалить `Копируем, потому что это существенно изменит их способ использования. Если вы опубликуете код в существующем репозитории, это нарушит вашу работу. ABI стабилен.

использоватьconsumeоператор дляконецпривязка переменныхизжизненный цикл

SE-0366 ВоляconsumeРасширяется докопироватьтипизлокальные переменныеипостоянный,этот Можетспособныйиметь利于那некоторый希望避免существоватьданныепроцесс передачисерединаэкранназадслучилосьмного retain/release Звоните разработчикам.

Оператор потребления выглядит следующим образом:

Язык кода:javascript
копировать
struct User {
    var name: String
}

func createUser() {
    let newUser = User(name: "Anonymous")
    let userCopy = consume newUser
    print(userCopy.name)
}

createUser()

Среди них линия критических темпов – да let userCopy Хорошо, он делает две вещи одновременно:

  1. будет ценить newUser копироватьприезжать userCopy
  2. конец newUser изжизненный цикл,поэтомулюбой Входитьодин步пытаться访问этобудет брошеношибка。

Это позволяет нам явно сказать компилятору: «Не позволяйте мне снова использовать это значение».

Более распространенные способы сделать да,использовать_Воля Что投入 black дыра - я не хочу копировать данные, я просто хочу пометить их как уничтоженные. похожий:

Язык кода:javascript
копировать
func consumeUser() {
    let newUser = User(name: "Anonymous")
    _ = consume newUser
}

Или используйте его при передаче значений в функции:

Язык кода:javascript
копировать
func createAndProcessUser() {
    let newUser = User(name: "Anonymous")
    process(user: consume newUser)
}

func process(user: User) {
    print("Processing \(name)…")
}

createAndProcessUser()

У этой черты есть два дополнительных момента, о которых стоит знать.

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

Язык кода:javascript
копировать
func greetRandomly() {
    let user = User(name: "Taylor Swift")

    if Bool.random() {
        let userCopy = consume user
        print("Hello, \(userCopy.name)")
    } else {
        print("Greetings, \(user.name)")
    }
}

greetRandomly()

Во-вторых,от Технически,consume Держатьделатьиздаобязательностьи Нетдаценить。на самом деле,Это означает, что если мы используем переменную,Мы можем повторно инициализировать переменную и нормализовать ее:

Язык кода:javascript
копировать
func createThenRecreate() {
    var user = User(name: "Roy Kent")
    _ = consume user

    user = User(name: "Jamie Tartt")
    print(user.name)
}

createThenRecreate()

AsyncStream и AsyncThrowingStream Удобство makeStream метод

SE-0388 для AsyncStream и AsyncThrowingStream добавить водининдивидуальныйновыйиз makeStream() метод,Долженметод Возвращает как сам поток, так и его продолжение.(continuation)。

Поэтому нам больше не нужно писать такой код:

Язык кода:javascript
копировать
var continuation: AsyncStream<String>.Continuation!
let stream = AsyncStream<String> { continuation = $0 }

Теперь мы можем получить оба:

Язык кода:javascript
копировать
let (stream, continuation) = AsyncStream.makeStream(of: String.self)

Это существование требует, чтобы существование было доступно вне текущего контекста, где продолжение особенно популярно.,Напримерсуществовать Неттакой жеизметодсередина。Например,Раньше мы могли бы написать простой генератор чисел,так,Требуется продолжение для хранения атрибута для собственного из.,для того, чтобы иметь возможность queueWork() Он вызывается в методе:

Язык кода:javascript
копировать
struct OldNumberGenerator {
    private var continuation: AsyncStream<Int>.Continuation!
    var stream: AsyncStream<Int>!

    init() {
        stream = AsyncStream(Int.self) { continuation in
            self.continuation = continuation
        }
    }

    func queueWork() {
        Task {
            for i in 1...10 {
                try await Task.sleep(for: .seconds(1))
                continuation.yield(i)
            }

            continuation.finish()
        }
    }
}

использоватьновыйиз makeStream(of:) метод, этот код становится еще проще:

Язык кода:javascript
копировать
struct NewNumberGenerator {
    let (stream, continuation) = AsyncStream.makeStream(of: Int.self)

    func queueWork() {
        Task {
            for i in 1...10 {
                try await Task.sleep(for: .seconds(1))
                continuation.yield(i)
            }

            continuation.finish()
        }
    }
}

для Clock добавить в sleep(for:) метод

SE-0374 для Swift из Clock протоколдобавить С новым методом расширения мы лучше приостанавливаем выполнение на указанное количество секунд, а также продлеваем его в зависимости от продолжительности. Task Спите с особым одобрением толерантности.

Clock Изменения небольшие, но очень специфичные, особенно если смоделировать их во время тестирования. Clock Пример устранения задержек, которые в противном случае существовали бы в производственных средах.

Например, эту отдельную категорию можно использовать с любым типом. Clock Создайте и используйте это перед запуском операции сохранения. Clock Спать:

Язык кода:javascript
копировать
class DataController: ObservableObject {
    var clock: any Clock<Duration>

    init(clock: any Clock<Duration>) {
        self.clock = clock
    }

    func delayedSave() async throws {
        try await clock.sleep(for: .seconds(1))
        print("Saving…")
    }
}

потому чтодляэтоиспользовать Понятно any Clock<Duration>,таксейчассуществовать Можетсуществоватьпроизводственная средасерединаиспользоватькартина ContinuousClock Таково из вещей, но существование проверь себя из DummyClock,существовать那внутриты Можетпренебрегатьвсеизsleep() команда для быстрого выполнения тестов.

существоватьстарая версияиз Swift , теоретический эквивалент кода да try await clock.sleep(until: clock.now.advanced(by: .seconds(1))),Но в данном примере это не работает,потому чтодля clock.now Недоступно, потому что для Swift Я не знаю, какой именно типиз Clock。

Что касается права Task Сон меняется, это означает, что мы можем написать такой код:

Язык кода:javascript
копировать
try await Task.sleep(until: .now + .seconds(1), tolerance: .seconds(0.5))

Упроститьдля:

Язык кода:javascript
копировать
try await Task.sleep(for: .seconds(1), tolerance: .seconds(0.5))

Отменить группу задач

SE-0381 добавить вновыйиз Может Отменить группу задача, исправил текущую API Дефект в индивидуальном важном: существование. Задачи, созданные в группе задач, будут автоматически отброшены и уничтожены после завершения, что означает, что они будут выполняться в течение длительного времени (или как Web Таким образом, сервер может работать вечно) из групп задач не будет происходить утечка памяти с течением времени.

использоватьоригинальныйиз withTaskGroup() API индивидуальная проблема может возникнуть, потому что для Swift только когда мы звоним next() или Просмотрите группу задач из подзадач, прежде чем отбрасывать подзадачи и их результаты. Если все подзадачи в данный момент выполняются, вызовите next() приведет к приостановке выполнения кода, поэтому у нас есть проблема: вы хотите, чтобы сервер всегда прослушивал соединения, чтобы он мог добавить в задачах для их обработки, но вам также придется время от времени останавливать и очищать старые задачи, которые были выполнены.

существовать Swift 5.9 До,этотиндивидуальный Проблема не чистаяизрешение。Swift 5.9 добавить в withDiscardingTaskGroup() и withThrowingDiscardingTaskGroup() Функция создания новых из группу задача. Эти группы задач будут автоматически отбрасывать и уничтожать каждую отдельную задачу после ее завершения, без необходимости вызывать ее вручную. next() потреблять его.

для Сообщите вам, что вызывает эту проблемуиз,Мы можем реализовать простой монитор каталогов,это永远цикли报告добавить вили Удалитьизлюбой файлили Оглавлениеизимя:

Язык кода:javascript
копировать
struct FileWatcher {
    // The URL we're watching for file changes.
    let url: URL

    // The set of URLs we've already returned.
    private var handled = Set<URL>()

    init(url: URL) {
        self.url = url
    }

    mutating func next() async throws -> URL? {
        while true {
            // Read the latest contents of our directory, or exit if a problem occurred.
            guard let contents = try? FileManager.default.contentsOfDirectory(at: url, includingPropertiesForKeys: nil) else {
                return nil
            }

            // Figure out which URLs we haven't already handled.
            let unhandled = handled.symmetricDifference(contents)

            if let newURL = unhandled.first {
                // If we already handled this URL then it must be deleted.
                if handled.contains(newURL) {
                    handled.remove(newURL)
                } else {
                    // Otherwise this URL is new, so mark it as handled.
                    handled.insert(newURL)
                    return newURL
                }
            } else {
                // No file difference; sleep for a few seconds then try again.
                try await Task.sleep(for: .microseconds(1000))
            }
        }
    }
}

Тогда мы сможем существовать индивидуально, просто используя его.,для краткости,нас Только Распечатать URL Без выполнения какой-либо сложной обработки:

Язык кода:javascript
копировать
struct FileProcessor {
    static func main() async throws {
        var watcher = FileWatcher(url: URL(filePath: "/Users/twostraws"))

        try await withThrowingTaskGroup(of: Void.self) { group in
            while let newURL = try await watcher.next() {
                group.addTask {
                    process(newURL)
                }
            }
        }
    }

    static func process(_ url: URL) {
        print("Processing \(url.path())")
    }
}

Это будет работать вечно,Или, по крайней мере, до тех пор, пока пользователь не завершит работу программы и каталог, который мы отслеживаем, больше не будет доступен. Но да,потому чтодляэтоиспользовать Понятно withThrowingTaskGroup(),такиметьодининдивидуальныйвопрос:Каждый Второсортныйвызов addTask() Новая подзадача создается каждый раз, а потому для она нигде не вызывается group.next(),Таким образом, эти подзадачи никогда не уничтожаются. Этот код будет постепенно съедать все больше и больше памяти (возможно, всего несколько сотен байт за раз).,До финальной версии операционной системы из RAM Измучен, вынужден прекратить программу.

использовать Отменить группу задача может полностью решить эту индивидуальную задачу: просто добавьте withThrowingTaskGroup(of: Void.self) Заменить для withThrowingDiscardingTaskGroup,Каждая подзадача будет автоматически уничтожена после ее завершения.

на самом деле,Эта отдельная проблема в основном возникает в существующем серверном коде.,Сервер должен иметь возможность принимать новые соединения.,Также плавно обрабатывайте существующие соединения.

Swift 5.8

Удалить ограничения на переменные в построителе результатов

SE-0373 Расслабленныйсуществовать приводит к некоторым ограничениям при использовании переменных в построителе. Лучшее, о чем мы писали ранее, было бы запрещено компилятором изкода.

Например,существовать Swift 5.8 середина,Мы можем создать конструктор напрямую, используя ленивую переменную.,Как показано ниже:

Язык кода:javascript
копировать
struct ContentView: View {
    var body: some View {
        VStack {
            lazy var user = fetchUsername()
            Text("Hello, \(user).")
        }
        .padding()
    }

    func fetchUsername() -> String {
        "@twostraws"
    }
}

Это показывает индивидуальную концепцию,но не дает никаких преимуществ,потому чтодлявсего ленивых переменныхдаодеялоиспользовать——существовать Долженкодсерединаиспользовать lazy var и let никакой разницы。хотеть Понятноразвязатьэто Реальность际иметьиспользоватьизместонуждатьсяодининдивидуальныйдольшеизкод Пример,Как показано ниже:

Язык кода:javascript
копировать
// Пользователи — это активные подписчики, неактивные подписчики, и мы пока не знаем их статуса.
enum UserState {
    case subscriber, nonsubscriber, unknown
}

// о Два небольших сообщения от пользователя из
struct User {
    var id: UUID
    var username: String
}

struct ContentView: View {
    @State private var state = UserState.unknown

    var body: some View {
        VStack {
            lazy var user = fetchUsername()

            switch state {
            case .subscriber:
                Text("Hello, \(user.username). Here's what's new for subscribers…")
            case .nonsubscriber:
                Text("Hello, \(user.username). Here's why you should subscribe…")
                Button("Subscribe now") {
                    startSubscription(for: user)
                }
            case .unknown:
                Text("Sign up today!")
            }
        }
        .padding()
    }

    // Пример функции, выполнит сложную работу
    func fetchUsername() -> User {
        User(id: UUID(), username: "Anonymous")
    }

    func startSubscription(for user: User) {
        print("Starting subscription…")
    }
}

Этот метод решает проблему, возникающую в альтернативе существования:

  • Если мы не будем использовать lazy,Так fetchUsername() Волясуществовать state извсетри видаслучай Всеодеяловызов,Прямо сейчасделатьсуществоватьодиндобрыйслучайэто没иметьодеялоиспользовать。
  • если мы удалим lazy и будет fetchUsername() изпозвонить и поставитьсуществоватьдваиндивидуальный case середина,Затем мы будем копировать код — для простого однострочного кода это не большая проблема.,Но вы можете себе представить, насколько это будет сложнее из-за проблем в вашем коде.
  • если мы будем user Перемещено в вычисляемое свойство, затем оно будет вызываться снова, когда пользователь нажимает кнопку «Подписаться сейчас».

Это изменение такжепозволятьнассуществоватьконструктор результатовсерединаиспользоватьсвойствооберткаиместный расчетсвойство,Хотя я подозреваю, что они не очень полезны. Например,сейчассуществоватьпозволятьнижетипизкод:

Язык кода:javascript
копировать
struct ContentView: View {
    var body: some View {
        @AppStorage("counter") var tapCount = 0

        Button("Count: \(tapCount)") {
            tapCount += 1
        }
    }
}

Но да, хотя это приведет к UserDefaults Значение меняется при каждом щелчке мыши, но используется таким образом @AppStorage приводит не к каждому tapCount При изменении body Свойства отзываются - мы из UI Не будет автоматически обновляться для отражения изменений. Автоматически обновляется с учетом изменений.

Функция обратного развертывания

SE-0376 добавить водининдивидуальныйновыйиз @backDeployed Атрибут, это разрешено вновую версию изframeworkиспользоватьновую API. По принципу работы он записывает код функции в двоичный файл вашего приложения, затем выполняет проверку во время выполнения: если ваша пользовательская версия операционной системы достаточно новая, тогда будет использовать собственную версию функции системы, иначе буду использоватькопировать в двоичную версию вашего приложения.

Apple предоставляет некоторые новые функции в более ранних операционных системах в порядке ретроспективы.,Но я признаюдляэтоти Нетда Чтопанацея——@backDeployed Доступно только для функции, метода, индекса и вычисляемых свойств, поэтому, хотя он может идеально подойти для небольших API измениться, например iOS 16.1 серединапредставлятьиз fontDesign() модификатор, но он не применяется ни к одному коду, требующему использования новой типизации, например, зависит от новой ScrollBounceBehavior Структура из нового scrollBounceBehavior() модификатор.

Например,iOS 16.4 для Text представлять Понятно monospaced(_ isActive:) . Если это использует `@backDeployed`,SwiftUI Команды могут убедиться, что модификатор доступен для подтверждения, которое им действительно необходимо для реализации кода, как можно скорее. SwiftUI версия следующая:

Язык кода:javascript
копировать
extension Text {
    @backDeployed(before: iOS 16.4, macOS 13.3, tvOS 16.4, watchOS 9.4)
    @available(iOS 14.0, macOS 11, tvOS 14.0, watchOS 7.0, *)
    public func monospaced(_ isActive: Bool) -> Text {
        fatalError("Implementation here")
    }
}

еслитак Реальностьсейчасмодификатор,существоватьвремя выполнения Swift буду использовать SwiftUI из Системной копии, если у нее уже есть этот модификатор, в противном случае используйте обратное развертывание из предыдущей версии. iOS 14.0 Похожие версии. На самом деле, хотя это и не открывает ничего нового, похоже, что ретроактивное развертывание — простой вариант, но мы не знаем. SwiftUI существуют внутреннеиспользоватьwhattype, поэтому трудно предсказать, что можно, а что нельзя развернуть задним числом. существоватьвнутреннийиспользовать Чтотип,Поэтому сложно предсказать, что можно будет развернуть назад.,Что запрещено.

weak selfПосле развязывания,поддерживать Скрытыйself

SE-0365 проходитьразрешено в слабый self Capture распаковывается изplaceuse неявно selfКпозволятьнасотзакрытиесередина Удалять `self。

Язык кода:javascript
копировать
class TimerController {
    var timer: Timer?
    var fireCount = 0

    init() {
        timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] timer in
            guard let self else { return }
            print("Timer has fired \(fireCount) times")
            fireCount += 1
        }
    }
}

существоватьSwift 5.8 доиз Версия,должениспользоватьself.fireCount

Упрощенный магический идентификатор файла

SE-0274упрощать Понятно #fileприходит магический идентификаториспользоватьModule/Filename,НапримерMyApp/ContentView.swift。до#fileСодержит полныйизпуть,если/Users/xxx/Desktop/yyy/ContentView.swift。 Оно очень длинное и содержит некоторую личную информацию.

Если вы хотите использовать старый полный путь,Можетиспользовать#filePath

Язык кода:javascript
копировать
// New behavior, when enabled
print(#file)

// Old behavior, when needed
print(#filePath)

Уведомление:В настоящее время эта индивидуальная функция не включена по умолчанию.,SE-0362добавлять Понятноиндивидуальныйодининдивидуальный-enable-upcoming-featureизскомпилировать флаги для включенияновыйхарактеристика,Если вам нужна эта индивидуальная функция,Можетиспользовать-enable-upcoming-feature ConciseMagicFile

Существуют параметры класса, которые можно использовать опционально.

SE-0375Расширять Понятно Swift 5.7 из Функция, которую лучше использовать в протоколе, вызывает функцию generics, благодаря которой исправлена ​​небольшая, но раздражающая несогласованность: Swift 5.7 Не отдавайте предпочтение дополнительному типу использования этой поездки, но Swift 5.8 тогда разрешили.

подиз Нет Можетвыбирать`T` функциясуществоватьSwift Его можно нормально использовать в 5.7.

Язык кода:javascript
копировать
func double<T: Numeric>(_ number: T) -> T {
    number * 2
}

let first = 1
let second = 2.0
let third: Float = 3

let numbers: [any Numeric] = [first, second, third]

for number in numbers {
    print(double(number))
}

В Swift 5.8 также можно использовать необязательные параметры.

Язык кода:javascript
копировать
func optionalDouble<T: Numeric>(_ number: T?) -> T {
    let numberToDouble = number ?? 0
    return  numberToDouble * 2
}

let first = 1
let second = 2.0
let third: Float = 3

let numbers: [any Numeric] = [first, second, third]

for number in numbers {
    print(optionalDouble(number))
}

В приведенном выше коде Swift 5.7 сообщит об ошибке «Введите «любой числовой» не может соответствовать «числовому».

Типы коллекций поддерживают принудительное преобразование вниз

Swift 5.8развязать决Понятно Досуществоватьопределенныйнекоторыйслучай Нетпозволять Кастинг коллекции——Например Воля ClassA Приведение массива для унаследовано от ` ClassA` из Другой вид типизации массива.

Язык кода:javascript
копировать
class Pet { }
class Dog: Pet {
    func bark() { print("Woof!") }
}

func bark(using pets: [Pet]) {
    switch pets {
    case let pets as [Dog]:
        for pet in pets {
            pet.bark()
        }
    default:
        print("No barking today.")
    }
}

существовать До,этотвнутри会报错“Collection downcast in cast pattern is not implemented; use an explicit downcast to '[Dog]' instead.”。 нуждатьсяиспользоватьif let dogs = pets as? [Dog] { из Грамматики подойдет.

Swift 5.7

if let快捷развязать Можетвыбирать包

SE-0345 в правительстве появился новый синтаксис сокращений для использования if let и guard let Распакуйте необязательные значения в одноимённые теневые переменные. Это означает, что теперь мы можем написать такой код:

Язык кода:javascript
копировать
var name: String? = "Linda"

if let name {
    print("Hello, \(name)!")
}

это изменение Нетподходящийиспользуется дляобъект Внутриизсвойство,этотиметь в видутакизкод Воля Не могущий Работа:

Язык кода:javascript
копировать
структура пользователя {
    имя переменной: String
}

пусть пользователь: Пользователь? = Пользователь(имя: «Линда»)

// Начальная работа
если пусть user.name {
    print("Добро пожаловать, \(user.name)!")
}

Улучшения вычета типа замыкания

SE-0326 значительно улучшено Swift существоватьзакрытиесерединаиспользоватьпараметритипсделать выводизспособность,делатьпридетсясуществовать Можетмногослучай,нас Нет необходимости явно указывать вводивыходтип.этотделатьпридетсякод Более краткий,Легче читать.

Swift 5.7 можно без ошибок написать так:

Язык кода:javascript
копировать
let scores = [100, 80, 85]

let results = scores.map { score in
    if score >= 85 {
        return "\(score)%: Pass"
    } else {
        return "\(score)%: Fail"
    }
}

В предыдущих версиях необходимо было четко указать тип возвращаемого значения:

Язык кода:javascript
копировать
let oldResults = scores.map { score -> String in
    if score >= 85 {
        return "\(score)%: Pass"
    } else {
        return "\(score)%: Fail"
    }
}

Clock, Instant, Duration

SE-0329 у правительства есть новый, стандартизированный способ цитирования Swift Среднее по времени и продолжительности. Как следует из названия, он разделен на три основных компонента:

  • Clock выражатьодиндобрый衡量时间流逝из Способ。Внутри置Понятнодвадобрый:непрерывные часы Прямо сейчасделатьсуществовать Отсчет времени также будет продолжаться, когда система находится в спящем режиме.,Пауза часов не происходит.
  • Мгновенный представляет собой точный момент времени.
  • Duration Продолжительность означает два индивидуальных Instant Прошло время между ними.

для многих людей,Самым простым из приложений будет недавно обновленный Task API.,Теперь можно указать время сна более разумным способом, чем наносекунды:

Язык кода:javascript
копировать
try await Task.sleep(until: .now +  .seconds(1), clock: .continuous)

этотиндивидуальныйновыйиз API Также дает возможность указать уровень допуска, который позволяет системе немного подождать после крайнего срока перехода в режим сна, чтобы максимизировать энергоэффективность. Так что если мы хотим хотя бы поспать 1 секунд, но, надеюсь, продлится в общей сложности 1.5 Секунды, мы бы написали:

Язык кода:javascript
копировать
try await Task.sleep(until: .now + .seconds(1), tolerance: .seconds(0.5), clock: .continuous)

Совет: этот допуск только увеличивает время сна по умолчанию, исходя из того, что система существует как минимум после 1. секунды.

Хотя этого еще не произошло, похоже, что старый API на основе nanoсекунды в ближайшем будущем будет заменен на Устарело.

Часы также полезны для измерения чего-то конкретного, что очень полезно, если вы хотите показать пользователям, например, сколько времени потребовалось для экспорта файла:

Язык кода:javascript
копировать
let clock = ContinuousClock()

let time = clock.measure {
    // complex work here
}

print("Took \(time.components.seconds) seconds")

Большие улучшения в регулярных выражениях

Swift 5.7 имеет ряд улучшений, связанных с регулярными выражениями.,极大земля改Входить Понятнонасиметь дело снитьиз Способ。

  • SE-0350 представлять Понятноодининдивидуальныйновыйиз Regex тип
  • SE-0351 возвышениеодининдивидуальный, движимый строителем результатов DSL для создания регулярных выражений.
  • SE-0354 добавить виспользовать /.../ без прохождения Regex Возможность создания регулярных выражений строк.
  • SE-0357 добавить в Можетмногона основетольконовыражениеизновыйнитьиметь дело салгоритм。

первый,насиметь Понятноодиннекоторыйновыйизнитьиметь дело сметод:

Язык кода:javascript
копировать
let message = "the cat sat on the mat"
print(message.ranges(of: "at"))
print(message.replacing("cat", with: "dog"))
print(message.trimmingPrefix("the "))

Мощная идея: мы можем использовать регулярные выражения:

Язык кода:javascript
копировать
print(message.ranges(of: /[a-z]at/))
print(message.replacing(/[a-m]at/, with: "dog"))
print(message.trimmingPrefix(/The/.ignoresCase()))

Кроме regex Литералы, Свифт Также предоставляет индивидуальное специализированное Regex тип.

Язык кода:javascript
копировать
do {
    let atSearch = try Regex("[a-z]at")
    print(message.ranges(of: atSearch))
} catch {
    print("Failed to create regex")
}

Есть одно ключевое отличие:

  • когданасиспользовать Regex от String при создании регулярного выражения в Swift долженсуществоватьвремя выполненияразвязать析нитьопределитьэтоотвечать Должениспользоватьиз Реальность际выражение。
  • Для сравнения, используйте regex буквальныйпозволять Swift существуют время компиляции, проверяющее вас из регулярное выражение: оно может проверить regex Не содержит ошибок, а также понимает, что будет содержать точные совпадения.

поэтомунас Можетнравиться下использовать,Буквально из режима.

Язык кода:javascript
копировать
let search1 = /My name is (.+?) and I'm (\d+) years old./
let greeting1 = "My name is Taylor and I'm 26 years old."

if let result = try? search1.wholeMatch(in: greeting1) {
    print("Name: \(result.1)")
    print("Age: \(result.2)")
}

Уведомление,resultиз tuple,Можетпроходить.1и.2 из Способ Приходить Цитироватьнасизсоответствовать(.0выражатьвсеиндивидуальныйсоответствоватьизнить)

Мы даже можем назвать совпадения:

Язык кода:javascript
копировать
let search2 = /My name is (?<name>.+?) and I'm (?<age>\d+) years old./
let greeting2 = "My name is Taylor and I'm 26 years old."

if let result = try? search2.wholeMatch(in: greeting2) {
    print("Name: \(result.name)")
    print("Age: \(result.age)")
}

Swift Можно даже передать такой метод, как SwiftUI из DSL из СпособсоздаватьRegex。

Язык кода:javascript
копировать
import RegexBuilder

let search3 = Regex {
    "My name is "

    Capture {
        OneOrMore(.word)
    }

    " and I'm "

    Capture {
        OneOrMore(.digit)
    }

    " years old."
}

настраивать,МожетдаиспользоватьTryCaptureи НетдаCapture,Сотрудничать с методом трансформации

Язык кода:javascript
копировать
let search4 = Regex {
    "My name is "

    Capture {
        OneOrMore(.word)
    }

    " and I'm "

    TryCapture {
        OneOrMore(.digit)
    } transform: { match in
        Int(match)
    }

    " years old."
}

Даже совпадающие имена могут быть выполнены:

Язык кода:javascript
копировать
let nameRef = Reference(Substring.self)
let ageRef = Reference(Int.self)

let search5 = Regex {
    "My name is "

    Capture(as: nameRef) {
        OneOrMore(.word)
    }

    " and I'm "

    TryCapture(as: ageRef) {
        OneOrMore(.digit)
    } transform: { match in
        Int(match)
    }

    " years old."
}

if let result = greeting1.firstMatch(of: search5) {
    print("Name: \(result[nameRef])")
    print("Age: \(result[ageRef])")
}

Тип вычета для значений по умолчанию

SE-0347 существования, общий параметр нашей функции существования использует значение по умолчанию.

Язык кода:javascript
копировать
func drawLotto2<T: Sequence>(from options: T = 1...49, count: Int = 7) -> [T.Element] {
    Array(options.shuffled().prefix(count))
}

Код верхнего уровня поддерживает параллельный код Concurrency.

SE-0343 Давайте существовать в коде верхнего уровняuseuse concurrency код.

Язык кода:javascript
копировать
import Foundation
let url = URL(string: "https://hws.dev/readings.json")!
let (data, _) = try await URLSession.shared.data(from: url)
let readings = try JSONDecoder().decode([Double].self, from: data)
print("Found \(readings.count) temperature readings")

параметртипподдерживать Нетпрозрачныйsomeзаявление

SE-0341 Объявление разблокированного параметра существуетиспользовать some Способность может заменить некоторые простые из общих мест.

Язык кода:javascript
копировать
func isSorted(array: [some Comparable]) -> Bool {
    array == array.sorted()
}

[some Comparable] Тип параметра означает, что эта функция подходит для приложений, содержащих Comparable протоколизировать типизируемый элемент из массива, это эквивалентно общему коду синтаксического сахара:

Язык кода:javascript
копировать
func isSortedOld<T: Comparable>(array: [T]) -> Bool {
    array == array.sorted()
}

Конечно, мы все еще можем писать более длинные и ограниченные расширения:

Язык кода:javascript
копировать
extension Array where Element: Comparable {
    func isSorted() -> Bool {
        self == self.sorted()
    }
}

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

поддерживать Болееформаиз Нетпрозрачныйsomeтип

SE-0328 Расширен диапазон непрозрачных результатов, которые можно использовать.

Например, теперь мы можем возвращать несколько отдельных непрозрачных типов одновременно:

Язык кода:javascript
копировать
import SwiftUI

func showUserDetails() -> (some Equatable, some Equatable) {
    (Text("Username"), Text("@twostraws"))
}

Мы также можем возвращать непрозрачные типы:

Язык кода:javascript
копировать
func createUser() -> [some View] {
    let usernames = ["@frankefoster", "@mikaela__caron", "@museumshuffle"]
    return usernames.map(Text.init)
}

Можно даже вернуть функцию, которая при вызове сама возвращает непрозрачный тип:

Язык кода:javascript
копировать
func createDiceRoll() -> () -> some View {
    return {
        let diceRoll = Int.random(in: 1...6)
        return Text(String(diceRoll))
    }
}

всепротоколprotocolВсе МожетделатьдляжитьсуществоватьтипExistential Type

SE-0309 сильно расслаблен Swift существоватьпротоколиметь Self илиассоциациятип Запрещено по запросуиспользоватьпротоколделатьдлятипизпредел,转Кодининдивидуальныйтолькона основеэтоих所Делатьизидентификациясвойствоилиметодограниченныйиз Модель。

Проще говоря, это означает, что следующий код становится законным:

Язык кода:javascript
копировать
let firstName: any Equatable = "Paul"
let lastName: any Equatable = "Hudson"

Equatable это с Self Запросить изпротокол,Это означает, что он предоставляет ссылку на конкретную функцию типизации, которая его использует. Например,Int соответствовать Equatable,таккогданасобъяснять 4 == 4 Когда мы на самом деле запускаем дасуществовать, человек принимает два отдельных целых числа и возвращает существование, когда они совпадают. true изфункция。

Swift Вы можете использовать что-то вроде func ==(first: Int, second: Int) -> Bool нет функции для достижения этой индивидуальной функциональности, но она плохо масштабируется - 他ихнуждатьсяписать几十индивидуальныйэтот Образецизфункция Приходитьиметь дело слогическое значениеценить、нить、Массив и т. д.。поэтому,Equatable протоколиметьодининдивидуальныйпохожийиз Требовать:func ==(lhs: Self, rhs: Self) -> Bool。по-английски,Это означает, что «вы должны быть в состоянии принять два экземпляра одного и того же тидивидуального,и告诉我этоихданеттакой же." Это может быть целое число, строка, логическое значение или логическое значение. Equatable из любого другого типаиз двух индивидуальных экземпляров.

чтобы избежать этой индивидуальной проблемыипохожийизвопрос,в любое время Self внесейчассуществовать Swift 5.7 Доизпротоколсередина,Компилятор не предпочитает существование нашего кода, используйте его.,Например:

Язык кода:javascript
копировать
let tvShow: [any Equatable] = ["Brooklyn", 99]

от Swift 5.7 Для начала этот код дапозволятьиз, теперь предел существования отложен до тех пор, пока вы не попробуете существовать. Swift Необходимо фактически реализовать его ограничения из ситуации localusetypez. Это значит, что мы не можем писать firstName == lastName,Потому что это похоже на то, что я сказал,== Необходимо убедиться, что в нем есть два экземпляра одного и того же типа для «Работа» и «Использовать». any Equatable Мы скрыли данные из точного типа.

Однако,Мы получаем возможность выполнять проверки данных во время выполнения.,Чтобы определить конкретный контент, с которым мы имеем дело. существующиеus из смешанного массиваиз случая,Мы можем написать такой код:

Язык кода:javascript
копировать
for item in tvShow {
    if let item = item as? String {
        print("Found string: \(item)")
    } else if let item = item as? Int {
        print("Found integer: \(item)")
    }
}

или ВОЗсуществоватьнасиздваиндивидуальныйнитьизслучай,нас Можетиспользоватьэтотиндивидуальный:

Язык кода:javascript
копировать
if let firstName = firstName as? String, let lastName = lastName as? String {
    print(firstName == lastName)
}

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

Язык кода:javascript
копировать
func canBeIdentified(_ input: any Sequence) -> Bool {
    input.allSatisfy { $0 is any Identifiable }
}

Короче говоря, SE-0309 расслабленный Swift Для тех, у кого есть Self илиассоциациятип Запросить изпротоколделатьдлятиписпользоватьиз лимита.этотделатьпридетсянас Можетболее свободноиспользоватьэтотнекоторыйпротокол,Пока мы не выполняем каких-либо конкретных задач, чтобы понять внутренние операции типа. так,Мы можем писать более гибкий код,И все это при сохранении безопасности.

Упрощение однородных типов первичных ассоциаций

SE-0346 для кавычек есть определенная ассоциация типизпротоколдобавить вновыйиз、Проще с точки зрения синтаксиса.

Например,Если мы пишем из кодированного кеша разные типизданные разными способами,Мы могли бы начать так:

Язык кода:javascript
копировать
protocol Cache<Content> {
    associatedtype Content

    var items: [Content] { get set }

    init(items: [Content])
    mutating func add(item: Content)
}

Уведомление,существование протокола выглядит как протокол, так и общий тип - у него есть родственный тип,Там говорится, что соответствиетипу необходимо заполнить какую-то дыру.,Но исуществоватьугловые скобкисередина列вне Понятно Должентип:Cache<Content>

из части да в угловых скобках Swift Обратитесь к его основной связанной типизационной части, чтобы в ближайшее время понять, что не все связанные типы должны быть объявлены там существующими. Вместо этого вам следует перечислить только те словарные ключи и значения, которые изтипили, которые обычно особенно интересуют вызывающий код. Identifiable протокол из идентификатора типа.существовать в нашем примере, мы говорим, что мы из кеша из контента - Строки, изображения, пользователи и т. д. - это основной тип ассоциации.

в это время,Мы можем продолжать, как и раньше - мы можем создать некоторые кэши, которые нам нужны.,Затемсоздаватьодининдивидуальныйсоответствоватьпротоколиз Инструменттеломедленныйжитьтип,Как показано ниже:

Язык кода:javascript
копировать
struct File {
    let name: String
}

struct LocalFileCache: Cache {
    var items = [File]()

    mutating func add(item: File) {
        items.append(item)
    }
}

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

Язык кода:javascript
копировать
func loadDefaultCache() -> LocalFileCache {
    LocalFileCache(items: [])
}

Но часто мы хотим скрыть конкретные действия, которые делаем.,Как показано ниже:

Язык кода:javascript
копировать
func loadDefaultCacheOld() -> some Cache {
    LocalFileCache(items: [])
}

использовать some Cache дает нам возможность изменить конкретный кеш, который мы отправляем обратно, но SE-0346 позволятьнас Делатьиздасуществовать Инструменттелотип绝верноидентификацияи Нетпрозрачный返回тип相когда模糊之间поставлятьодининдивидуальныйсерединапромежуточная зона。так,Мы можем специализировать протокол,Как показано ниже:

Язык кода:javascript
копировать
func loadDefaultCacheNew() -> some Cache<File> {
    LocalFileCache(items: [])
}

поэтому,насоставаться Понятно Воля Приходить转移приезжать Неттакой жеиз Cache-conforming Возможности типизации, но мы ясно дали понять, что независимо от того, что выбрано, существование будет храниться внутри.

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

Язык кода:javascript
копировать
extension Cache<File> {
    func clean() {
        print("Deleting all cached files…")
    }
}

èОбщие ограничения:

Язык кода:javascript
копировать
func merge<C: Cache<File>>(_ lhs: C, _ rhs: C) -> C {
    print("Copying all files into a new location…")
    // now send back a new cache with items from both other caches
    return C(items: lhs.items + rhs.items)
}

Но самая полезная изда, SE-0358. Использование этих основных типов ассоциаций в Swift из стандартной библиотеки, поэтому SequenceCollection Каждый получит выгоду - мы можем написать Sequence<String> Запись не имеет ничего общего с точной последовательностью существованияиспользоватьизтипизкода.

границаизжитьсуществоватьтипExistential Type

SE-0353поставлять Понятнокомбинация SE-0309(всепротоколprotocolВсе МожетделатьдляжитьсуществоватьтипExistential Type) и SE-0346(Упрощение однородных типов первичных ассоциаций) изспособность,Может写внеany Sequence<String>

распределенныйизactorизоляция

SE-0336 и SE-0344 представлять Понятно actor Возможности работы в распределенной форме - использовать удаленный вызов процедуры (RPC) существовать Читайте и пишите в Интернете.свойствоиливызовметод。

Эта проблема настолько сложна, насколько вы себе представляете,ноиметь三点Можетделатьэто Изменятьпридется Полегче:

  1. Swift Метод «Позиционной прозрачности» фактически заставляет нас предполагать actor да Отдаленность от, по сути, существования не может быть определена при составлении actor далокальный или удаленный - В любом случае, мы просто используем то же самое из await Вызывается, если actor случается далокализация, тогда звонок будет сделан как для обычного местного actor функцияиметь дело с。
  2. Вместо того, чтобы заставлять нас строить себя из actor Система передачи, Apple для Мы предоставляем готовую индивидуальную реализацию. Хотя Apple Сказав, что они «в конечном итоге ожидают, что на сцену выйдет лишь несколько зрелых реализаций», но, к счастью, Swift Все распространяется в Китае actor Все функции с вамииспользоватьиз actor Трансмиссия не имеет значения.
  3. от actor Перейти к распределенному актеры, нам в основном просто нужно писать их по требованию distributed actor Затем distributed func

поэтому,Мы могли бы написать такой код, чтобы имитировать отслеживание системы торговых карточек:

Язык кода:javascript
копировать
// use Apple's ClusterSystem transport 
typealias DefaultDistributedActorSystem = ClusterSystem

distributed actor CardCollector {
    var deck: Set<String>

    init(deck: Set<String>) {
        self.deck = deck
    }

    distributed func send(card selected: String, to person: CardCollector) async -> Bool {
        guard deck.contains(selected) else { return false }

        do {
            try await person.transfer(card: selected)
            deck.remove(selected)
            return true
        } catch {
            return false
        }
    }

    distributed func transfer(card: String) {
        deck.insert(card)
    }
}

Из-за распределенного actor Вызвав функцию изthrows, мы можем гарантировать, что существуют вызовы person.transfer(card:) При удалении карты безопасности в Collector исключений не возникает.

Swift изTargetда позволяет легко разместить actor из Понятноразвязать Перейти к распределенному актер, но есть некоторые существенные различия, которые могут вас смутить.

первый,всераспределенныйфункциядолжениспользовать try и await Вызывается, даже если функция не отмечена для throwing,для Ошибка из-за сетевого вызова,Могут возникнуть неисправности.

Во-вторых,Все параметры распределенного метода и возвращаемые значения должны соответствовать выбранному вами процессу сериализации.,Например Codable。этотсуществоватьвремя компиляциипридетсяприезжатьисследовать,поэтому Swift Могу гарантировать, что это возможно удаленно actor Отправляйте и получайте данные.

третий,тыотвечать Должен考虑调всетыиз actor API для минимизации запросов данных. Например, если вы хотите читать распределенно actor из usernamefirstNameи lastName свойство,Вы должны предпочесть использовать один индивидуальный метод для запроса всех трех индивидуальных атрибутов.,Вместо того, чтобы делать их отдельными запросами атрибутов,Во избежание возможного многократного существования в сети туда и обратно.

result builder поддерживать buildPartialBlock

SE-0348 Значительно упрощает реализацию сложных результатов builder требует перегрузки, что тоже да Swift Расширенные регулярные выражения поддерживаются, возможно, отчасти по этой причине. SwiftUI Если команда адаптируется к этой особенности, она теоретически будет устранена. SwiftUI только самое 10 индивидуальный view из лимита.

для дал вам практический пример, вот упрощенная версия SwiftUI из ViewBuilder

Язык кода:javascript
копировать
import SwiftUI

@resultBuilder
struct SimpleViewBuilderOld {
    static func buildBlock<C0, C1>(_ c0: C0, _ c1: C1) -> TupleView<(C0, C1)> where C0 : View, C1 : View {
        TupleView((c0, c1))
    }

    static func buildBlock<C0, C1, C2>(_ c0: C0, _ c1: C1, _ c2: C2) -> TupleView<(C0, C1, C2)> where C0: View, C1: View, C2: View {
        TupleView((c0, c1, c2))
    }
}

Создал два индивидуальных buildBlock() из версии: Один индивидуальный принимает два индивидуальных представления, один индивидуальный принимает три индивидуальных представления. Фактически, SwiftUI Принимайте различные альтернативы, но ключ может быть только 10 индивидуальный。

Затем,Мы можем использовать функции или вычисляемые свойства для использования построителя результатов.,Как показано ниже:

Язык кода:javascript
копировать
@SimpleViewBuilderOld func createTextOld() -> some View {
    Text("1")
    Text("2")
    Text("3")
}

этотбуду использовать buildBlock<C0, C1, C2>() Варианты принимают все три индивидуальных Text просмотреть и вернуть все индивидуальные файлы, содержащие их TupleView。Однако,существоватьэтотиндивидуальныйупрощатьиз Примерсередина,ни за чтодобавить вчетвертыйиндивидуальный Text Просмотрите, потому что для меня не предусмотрено больше из перегрузок, типа SwiftUI Нетподдерживать 11 индивидуальныеили больше того же самого.

Это даиз buildPartialBlock() из действий, поскольку для него путь из Работы аналогичен последовательности из reduce() метод: имеет начальное значение «индивидуальный», затем уже будет добавлено содержимое по в прибыть Следующийиз Внутри容Приходить更новый Долженценить。

так,Мы можем создать индивидуальный новый конструктор результатов,Он знает, как принять индивидуальную точку зрения,И как совместить этот вид с другим индивидуальным видом:

Язык кода:javascript
копировать
@resultBuilder
struct SimpleViewBuilderNew {
    static func buildPartialBlock<Content>(first content: Content) -> Content where Content: View {
        content
    }

    static func buildPartialBlock<C0, C1>(accumulated: C0, next: C1) -> TupleView<(C0, C1)> where C0: View, C1: View {
        TupleView((accumulated, next))
    }
}

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

Язык кода:javascript
копировать
@SimpleViewBuilderNew func createTextNew() -> some View {
    Text("1")
    Text("2")
    Text("3")
}

Результат будет не совсем одинаковым: сначала индивидуальный пример мы получим индивидуальный TupleView<Text, Text, Text>,исейчассуществоватьнас Воляпридетсяприезжатьодининдивидуальный `TupleView<(TupleView<(Text, Text)>, Text)> `- одининдивидуальный TupleView Вложенныйсуществовать Другойодининдивидуальный TupleView Внутри.

tips: buildPartialBlock() да Swift изодинчасть,и не является частью какой-либо конкретной среды выполнения платформы,Так что, если вы примете это,Вы обнаружите, что его можно развернуть в более ранних версиях операционной системы.

Неявно открытые типы существования

SE-0352 позволять Swift Во многих случаях использование протокола вызывает универсальную функцию.

Подниматьиндивидуальныйпример,Вот отдельная простая из общей функции.,способный够иметь дело слюбойтипиз Numeric ценить:

Язык кода:javascript
копировать
func double<T: Numeric>(_ number: T) -> T {
    number * 2
}

Если мы вызовем это напрямую, например double(5),Так Swift Компилятор может выбрать специализацию функции - Из соображений производительности эффективно создавайте отдельный акцепт напрямую. Int из версии.

И SE-0352 изделатьиспользоватьдаразрешено в Мы знаем, что мы изданныесоответствовать протоколам случаев называем эту функцию, как показано ниже:

Язык кода:javascript
копировать
let first = 1
let second = 2.0
let third: Float = 3

let numbers: [any Numeric] = [first, second, third]

for number in numbers {
    print(double(number))
}

Swift Сохраните эти имена как тип существования: Вы существуетеиспользоватьизактуально данн. йтип находится внутри отдельного ящика, и когда мы вызываем метод в этом ящике, Swift 理развязатьэтоотвечать Должен Скрытыйземлясуществоватьвнутри коробкиизданныеначальствовызовметод。SE-0352 также расширяет эту функциональность для вызовов функций.:насциклсерединаизnumber ценитьдаодининдивидуальныйжитьсуществоватьтип(одининдивидуальный Включать IntDouble или Float из коробки), но Swift Возможность передать его дженерикам double() Функция, метод передаются в значении из поля.

Эта функциональность имеет свои ограничения. Например, этот код не может работать:

Язык кода:javascript
копировать
func areEqual<T: Numeric>(_ a: T, _ b: T) -> Bool {
    a == b
}

print(areEqual(numbers[0], numbers[1]))

Swift Невозможно определить, можно ли использовать эти два отдельных значения во время статической проверки (т.е. существуют во время компиляции) ==сравнивать,поэтомукод根本Не могущий构建。

Асинхронные недоступные свойства

SE-0340 Частично решено Swift и发Модельсередина Можетспособныйжитьсуществоватьизрискованная ситуация,лучше Мы типифунцию отметим для существования недоступно в асинхронном контексте,Потому что при таком использовании они могут вызвать проблемы. Если вы не используете локальное хранилище потоков, блокировки, мьютексы или семафоры.,В противном случае вы вряд ли станете владельцем этой недвижимости.,Но вы можете использовать этот атрибут из кода.,поэтому По меньшей мереценитьпридется Понятноразвязатьэтоизжитьсуществовать。

Чтобы пометить определенный контент как «существовать», недоступный в асинхронном контексте, пожалуйста, @available и Обычно вы выбираете платформу, Затемсуществовать в конце добавить в noasync。Например,У нас может быть индивидуальная функция для любой платформы.,Но существование может вызвать проблемы при асинхронном вызове.,поэтомунас Воляэтот Образецотметкаэто:

Язык кода:javascript
копировать
@available(*, noasync)
func doRiskyWork() {

}

Далее мы можем вызвать его как обычно из обычной функции синхронизации:

Язык кода:javascript
копировать
func synchronousCaller() {
    doRiskyWork()
}

Однако,Если мы попытаемся использовать асинхронную функцию, выполните ту же операцию.,Swift Будет выдана ошибка, поэтому этот код не будет работать:

Язык кода:javascript
копировать
func asynchronousCaller() async {
    doRiskyWork()
}

Эта защита является улучшением по сравнению с текущей ситуацией.,Но не стоит слишком на это полагаться,потому чтодляэто Нетпредотвратитнас Вложенныйвызовнасиз noasync функция, как показано ниже:

Язык кода:javascript
копировать
func sneakyCaller() async {
    synchronousCaller()
}

Это существование работает в асинхронном контексте,Но вызовите функцию синхронизации,Затем Может反过Приходитьвызов noasync функция doRiskyWork()

Swift 5.6

представлятьжитьсуществоватьтипanyключевые слова

SE-0335 представлять Понятноодининдивидуальныйновыйизключевые слова any Отметить месторождение существующего типа(экзистенциального тип). Эту индивидуальную характеристику немного сложно понять, и она также предвещает swift Последующие версии из break change。

протоколпозволять Указываем набор требований, которым должен соответствоватьизтип,Напримерэтоихдолженхотеть Реальностьсейчасизметод。поэтомунасчастонасчастоэтот Что написать:

Язык кода:javascript
копировать
protocol Vehicle {
    func travel(to destination: String)
}

struct Car: Vehicle {
    func travel(to destination: String) {
        print("I'm driving to \(destination)")
    }
}

let vehicle = Car()
vehicle.travel(to: "London")

Мы также можем использовать существующую функциюгенерал-лейтенантпротокол в качестве общего ограничения.,Это значит, что мы можем написать любой типданныйизкод.Например, удовлетворяющий указанному протоколиз., подкодподходящийиспользуется длялюбойудовлетворитьVehicle протоколизациялюбойтип:

Язык кода:javascript
копировать
func travel<T: Vehicle>(to destinations: [String], using vehicle: T) {
    for destination in destinations {
        vehicle.travel(to: destination)
    }
}

travel(to: ["London", "Amarillo"], using: vehicle)

Когда приведенный выше код компилируется, Swift Может Восприятиеприезжатькодсерединавызов ПонятноCarиз travel( )метод,Затем Можетоптимизациядляпрямойвызовtravel() ——Разновидность статического планирования, называемая для отправка)из процесса.

Вот еще один аналогичный способ:

Язык кода:javascript
копировать
let vehicle2: Vehicle = Car()
vehicle2.travel(to: "Glasgow")

нас任然создавать ПонятноCarизструктура,Да ПучокэтожитьмагазиндляVehicle。этот Неттолькодапростойодинизскрывать Понятноосновная информация,идаэтотиндивидуальныйVehicleстановиться Понятноодининдивидуальныйпозвони этодляжитьсуществоватьтип(existential type)Полныйновыйизтип:способный разместитьсоответствоватьVehicleпротоколизлюбойтипизлюбойценитьизновыйданныетип.

важный:житьсуществоватьтип(existential type)ипроходитьsomeключевые словазаявлениеиз Нетпрозрачныйтип(opaque тип) разные. Непрозрачный тип (непрозрачный type) представляет собой неизвестный из, конкретный изтип, который удовлетворяет указанному ограничению из. Несмотря на то, что да неизвестно, компилятор да гарантирует, что весь индивидуум единообразен во всех областях, и исиспользовать такой же, как и тип. Отсюда и непрозрачный тип (opaque. тип) может обеспечить более надежную гарантию и оптимизацию.

настакже Можетсуществоватьфункциясерединаиспользоватьжитьсуществоватьтип(existential type),Например:

Язык кода:javascript
копировать
func travel2(to destinations: [String], using vehicle: Vehicle) {
    for destination in destinations {
        vehicle.travel(to: destination)
    }
}

этотдобрый Способ Хотяидругойтиписпользовать Способоченькартина。Дафункциясерединаприниматьлюбойудовлетворитьиз`Vehicle`объект,Swift Невозможно выполнить описанную выше оптимизацию. Он может передавать только динамическое планирование (динамическое send)iz, поэтому он не так эффективен, как статическая отправка, описанная выше. Следовательно, Свифт в настоящий момент Версиясередина,Два варианта использования протоколизма очень похожи.,на самом делепомедленнееизжитьсуществовать Версияизфункцияпроще написать。

для решения этой индивидуальной проблемы с помощью Swift 5.6 дляжитьсуществоватьтип(existential type)представлять Понятноanyключевые слова,поэтомунас Сразу Можеткодсерединапоказыватьиз指вне Понятножитьсуществоватьиз Влияние。Следовать заиз Версияесли Нетиспользовать Предупредит。существует Swift 6 из может сообщить об ошибке,Требуйте четкой маркировки,Следуйте следующему методу записи:

Язык кода:javascript
копировать
let vehicle3: any Vehicle = Car()
vehicle3.travel(to: "Glasgow")

func travel3(to destinations: [String], using vehicle: any Vehicle) {
    for destination in destinations {
        vehicle.travel(to: destination)
    }
}

заполнитель типа

SE-0315представлять Понятнозаполнитель типаизконцепция,Определим тип существования, отображение указанного типа детали.,пусть остальноеизчастьпроходитьтипсделать вывод Приходить填充。типсделать выводизместоиспользовать_

заполнить типсуществовать Это полезно, когда компилятор может правильно определить только часть типа. Это может упростить написание типизаций.,И доступно только одобрение,_?

Язык кода:javascript
копировать
var results3: [_: [Int]] = [
    "Cynthia": [],
    "Jenny": [],
    "Trixie": [],
]

нуждаться Уведомлениеизда,в настоящий моментзаполнитель типавозвращаться Нетподдерживатьфункциязнак,Даты Может先写начальство_заполнитель,Пусть компилятор сделает вывод,Затемпозволять Xcode Предоставьте предложения по ремонту для завершения кода.

позволятьkeyНетдаString/IntизDictionaryтакже можетиспользоватьKeyedContainer

SE-0320 представлять Понятноодининдивидуальныйновыйиз CodingKeyRepresentable протокол, предпочтение будет иметь необычный String или Int ключизсловарная кодировкадляключконтрольный контейнер,и Нетда Нетключконтрольный контейнер。этотразвязать决Понятнодосуществоватькодированиеиметь Пользовательский элемент Подниматьилиструктураключиз Словарь Можетспособный遇приезжатьизвопрос。

проходитьдля Пользовательский элемент Подниматьилиструктура Реальностьсейчас CodingKeyRepresentable может гарантировать, что эти ключи обрабатываются правильно во время шифрования и декодирования протокола. Это делает JSON из вывода легче понять исуществовать Swift снаружииспользовать。

Например,из кода ниже,Swift Умеет правильно выполнить:

Язык кода:javascript
копировать
import Foundation

enum OldSettings: String, Codable {
    case name
    case twitter
}

let oldDict: [OldSettings: String] = [.name: "Paul", .twitter: "@twostraws"]
let oldData = try JSONEncoder().encode(oldDict)
print(String(decoding: oldData, as: UTF8.self))

Да Распечататьда["twitter","@twostraws","name","Paul"] Явно не соответствует ожидаемому.

ДаиспользоватьCodingKeyRepresentableпротоколназад。

Язык кода:javascript
копировать
enum NewSettings: String, Codable, CodingKeyRepresentable {
    case name
    case twitter
}

let newDict: [NewSettings: String] = [.name: "Paul", .twitter: "@twostraws"]
let newData = try! JSONEncoder().encode(newDict)
print(String(decoding: newData, as: UTF8.self))

Распечатать Сразусоответствоватьожидал Понятно:{"twitter":"@twostraws","name":"Paul”}

https://stackoverflow.com/questions/68466494/what-is-a-swift-un-keyed-container

Нетиспользовать#unavailableУсловное суждение

SE-0290 представлять Понятноодининдивидуальныйимядля #unavailable из Новая директива, она связана с #available Вместо этого некоторый код выполняется в случае сбоя проверки доступности. Это полезно в ситуациях, когда вы просто хотите запустить код, когда конкретная операционная система недоступна.

ииспользовать #available пустой true По сравнению с блоком, сейчас существование можно более лаконично использовать. #unavailable инструкция:

Язык кода:javascript
копировать
if #unavailable(iOS 15) {
    // делать iOS 14 Предыдущая версия нормальный код работыиз
}

Раньше вам приходилось использовать метод else пустого блока:

Язык кода:javascript
копировать
if #available(iOS 15, *) { } else {
    // Code to make iOS 14 and earlier work correctly
}

нуждаться Уведомлениеизда,и #available Неттакой же,#unavailable Нетпозволятьиспользовать Подстановочный знак платформы *,Потому что длясуществовать в данном случае,Это может привести к двусмысленности.

Дополнительные изменения в параллелизме

Swift 5.5 добавить в Можетмногооодновременно Функция,И 5.6 продолжает улучшать эти функции.,делатьэтоих更Безопасность、Более последовательный, а также для выхода в Swift 6 большего размера.、Будьте готовы к более революционным изменениям.

Максимальное изменение да SE-0337,цельсуществоватьдлянасизкодпоставлять Реальностьсейчас完Полный严格из Проверка параллелизмаиздорожная карта。этотда Инкрементальныйиз:ты Можетиспользовать @preconcurrency Импортируйте весь индивидуальный модуль и скажите Swift Модуль дасуществовать создан без учёта современных одновременно ситуаций, вы можете @preconcurrency отметкадляодининдивидуальныйдобрый、структура、свойство、методждать,Чтобы быть более избирательным, используйте.

Другойодининдивидуальныйтолькосуществоватьизменятьизполеда actor изиспользовать,потому чтодляпотому что SE-0327 из результатов, Swift 5.6 Теперь существуют будут выдавать предупреждение, если вы попытаетесь использовать @StateObject Реальность例化одининдивидуальный @MainActor свойства, например:

Язык кода:javascript
копировать
import SwiftUI

@MainActor class Settings: ObservableObject { }

struct OldContentView: View {
    @StateObject private var settings = Settings()

    var body: some View {
        Text("Hello, world!")
    }
}

этотиндивидуальныйпредупреждать Волясуществовать Swift 6 серединаобновлениедляошибка,Так что вы должны быть готовы отказаться от этого кода,改использоватьэтотиндивидуальный

Язык кода:javascript
копировать
struct NewContentView: View {
    @StateObject private var settings: Settings

    init() {
        _settings = StateObject(wrappedValue: Settings())
    }

    var body: some View {
        Text("Hello, world!")
    }
}

Несколько плагинов для управления пакетами Swift

Swift 5.6 Содержит серию Swift Package Manager из Улучшений, эти улучшения объединены добавить виспользовать Внешние инструменты сборкиизплагинподдерживатьиз Предварительный Функция。

ссылка

boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose