Swift 5.2 — что нового?

от автора

Первая бета Swift 5.2 только что появилась в Xcode 11.4 beta, и в ней произошли изменения в языке, наряду с сокращением размера кода и используемой памяти, а также появилась новая система диагностики, которая позволит быстрее выявлять ошибки.

Используем KeyPath выражения как функции

Определим такую структуру:

struct User {     let name: String     let age: Int     let bestFriend: String?      var canVote: Bool {         age >= 18     } }

Создадим несколько экземпляров нашей структуры и положим их в массив:

let eric = User(name: "Eric Effiong", age: 18, bestFriend: "Otis Milburn") let maeve = User(name: "Maeve Wiley", age: 19, bestFriend: nil) let otis = User(name: "Otis Milburn", age: 17, bestFriend: "Eric Effiong") let users = [eric, maeve, otis]

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

let userNames = users.map(\.name) print(userNames)

Ранее нам нужно было использовать замыкание:

let oldUserNames = users.map { $0.name }

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

let voters = users.filter(\.canVote)

А здесь мы получим всех, у кого есть лучший друг:

let bestFriends = users.compactMap(\.bestFriend)

Значения у определяемых пользователем типов

Создадим структуру Dice со свойствами lowerBound и upperBound, а затем добавим функцию callAsFunction. Таким образом, всякий раз при получении значения dice, мы будем получать случайное значение:

struct Dice {     var lowerBound: Int     var upperBound: Int      func callAsFunction() -> Int {         (lowerBound...upperBound).randomElement()!     } }  let d6 = Dice(lowerBound: 1, upperBound: 6) let roll1 = d6() print(roll1)

Здесь мы получим случайное число от 1 до 6, и это совершенно идентично прямому вызову callAsFunction(). То же самое мы могли бы сделать так:

let d12 = Dice(lowerBound: 1, upperBound: 12) let roll2 = d12.callAsFunction() print(roll2)

Swift автоматически подбирает верный вызов на основании того, как именно определена callAsFunction(). Например, вы можете добавить несколько параметров, менять возвращаемое значение, и даже, если нужно, помечать метод как mutating.

Здесь мы создадим структуру StepCounter, которая фиксирует число пройденных шагов и сигнализирует, достигло ли количество пройденных шагов 10,000:

struct StepCounter {     var steps = 0      mutating func callAsFunction(count: Int) -> Bool {         steps += count         print(steps)         return steps > 10_000     } }  var steps = StepCounter() let targetReached = steps(count: 10)

callAsFunction() поддерживает также throws и rethrows, и вы можете определить несколько callAsFunction() методов, как при обычной перегрузке.

У Subscript можно объявить аргументы по умолчанию

При добавлении subscripts к типу можно использовать аргументы по умолчанию. Например, если у нас есть структура PoliceForce с пользовательским subscript чтобы перечислять офицеров в подразделении, мы можем добавить параметр по умолчанию, чтобы возвращать его в случае чтения массива вне его границ:

struct PoliceForce {     var officers: [String]      subscript(index: Int, default default: String = "Unknown") -> String {         if index >= 0 && index < officers.count {             return officers[index]         } else {             return `default`         }     } }  let force = PoliceForce(officers: ["Amy", "Jake", "Rosa", "Terry"]) print(force[0]) print(force[5])

Здесь мы получим на выводе “Amy”, а затем “Unknown”, так как у нас нет элемента массива с индексом 5.

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

print(force[-1, default: "The Vulture"])

Новая и улучшенная диагностика

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

Для примера рассмотрим такой код:

struct ContentView: View {     @State private var name = 0      var body: some View {         VStack {             Text("What is your name?")             TextField("Name", text: $name)                 .frame(maxWidth: 300)         }     } }

Здесь мы пытаемся связать view TextField c целым State свойством, что неверно. Swift 5.1 выдаст в таком случае ошибку для модификатора frame() ‘Int’ is not convertible to ‘CGFloat?’, но Swift 5.2 и последующие верно распознают ошибку в биндинге $name: Cannot convert value of type ‘Binding’ to expected argument type ‘Binding’.

ссылка на оригинал статьи https://habr.com/ru/post/487552/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *