Pull to refresh

Что новенького в Swift 4.1

Reading time 4 min
Views 12K

Этот пост является вольным переводом статьи What’s new in Swift 4.1 by Paul Hudson


Swift 4.1 — первый минорный релиз Swift 4, который принес с собой некоторые полезные фишки, такие как автоматическое применение Equatable и Hashable, условные соответствия и т.д.


Убедитесь, что поставили себе как минимум Xcode 9.3, затем создайте новый playground. Давайте посмотрим на новые фичи этой версии...


Equatable и Hashable


Протокол Equatable позволяет сравнивать одну сущность с другой. Когда мы говорим 5 == 5, Swift понимает, что это значит потому что Int соответствует протоколу Equatable, а значит реализует функцию, которая описывает, что означает "==" для сущностей типа Int.

Реализация Equatable в ваших собственных типах (структурах, перечислениях) позволяет работать с ними также как со строками, массивами, числами и т.п. И будет хорошо, если ваши структуры будут соответствовать протоколу Equatable, чтобы лучше соответствовать общему концепту типов, которые передаются по значению.


Однако реализация Equatable может быть не слишком элегантной. Например у нас есть такая структура:


struct Person {
    var firstName: String
    var middleName: String
    var age: Int
    var city: String
}

И если у вас есть две сущности типа Person и вы хотите сравнить их, вам нужно сравнивать все четыре свойства, вот так:


struct Person: Equatable {
    var firstName: String
    var lastName: String
    var age: Int
    var city: String

    static func ==(lhs: Person, rhs: Person) -> Bool {
        return lhs.firstName == rhs.firstName && lhs.lastName == rhs.lastName && lhs.age == rhs.age && lhs.city == rhs.city
    }
}

Это сложно даже прочитать, не то что написать.


К счастью, в Swift 4.1 возможно автоматическое соответствие для Equatable, метод == будет сгенерирован автоматически и будет сравнивать все свойства первой сущности со всеми свойствами второй, так же как описано выше. Все что вам нужно сделать — добавить Equatable к вашему типу, а Swift сделает все остальное.


Естественно, вы можете реализовать свой вариант метода ==. Например, если у вашего типа есть свойство id, которое однозначно идентифицирует сущность — вы могли бы написать ==, чтобы сравнивать только это свойство, вместо того, чтоб Swift выполнял лишнюю работу.


Аналогично Equatable, в Swift 4.1 также "завезли" поддержку Hashable. Теперь hashValue может генерироваться автоматически для соответствия этому протоколу. Hashable обычно раздражает, ведь вам нужно вернуть уникальный (более-менее уникальный) хэш для каждой сущности. Это важно, потому что позволит использовать ваши сущности как ключи для словарей, или позволит хранить сущности во множествах (sets).


Раньше нужно было написать что-то типа такого:


var hashValue: Int {
    return firstName.hashValue ^ lastName.hashValue &* 16777619
}

Учитывая это, вам теперь вряд ли понадобится писать свою реализацию hashValue в Swift 4.1, но если это все-таки понадобится вы сможете это сделать (аналогично == в Equatable).


Примечание: Добавляйте по необходимости эти протоколы к своим типам, и не забывайте, что все поля ваших типов тоже должны соответствовать им.


Больше информации можете найти тут: Swift Evolution proposal SE-0185.


Условные соответствия


В Swift Evolution proposal SE-0143 предложили условные соответствия, и они теперь есть в Swift 4.1. Это мощная возможность, которая будет полезна очень многим. С ней теперь заработают вещи, которые не работали раньше. Например, в Swift 4.0 такой код не будет компилироваться:


var left: [String?] = ["Andrew", "Lizzie", "Sophie"]
var right: [String?] = ["Charlotte", "Paul", "John"]
left == right

Все потому, что String и [String] — соответствуют Equatable, а вот [String?] — нет. Условное соответствие означает, что тип будет соответствовать протоколу, пока удовлетворяется определенное условие. Это означает, что если элементы массива соответствуют Equatable — весь массив соответствует Equatable.


Условное соответствие распространено и на протокол Codable, и это сделает некоторые вещи более безопасными. Взглянем на этот код:


struct Person {
    var name = "Taylor"
}

var people = [Person()]
var encoder = JSONEncoder()
try encoder.encode(people)

У нас есть массив из одного элемента типа Person, и пытаемся преобразовать этот массив в JSON. Такой код спокойно компилируется в Swift 4.0, но в рантайме вы получите ошибку, потому что Person не соответствует протоколу Codable. Swift 4.1 решает эту проблему: Optional, Array, Dictionary и Set теперь соответствуют протоколу Codable только если их содержимое соответствует этому протоколу, поэтому в Swift 4.1 такой код просто не скомпилируется.


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


flatMap теперь (почти) compactMap


flatMap() полезен для множества вещей в Swift 4.0, но его главная возможность — преобразовывать сущности в коллекции, попутно удаляя из результата nil-ы.


В Swift Evolution proposal SE-0187 предложили изменить это, и в Swift 4.1 flatMap() переименован в compactMap(), чтобы более понятно передать его смысл.


Например:


let array = ["1", "2", "Fish"]
let numbers = array.compactMap { Int($0) }

Это создаст массив с элементами типа Int, который будет содержать числа 1 и 2, потому что "Fish" при преобразование в Int вернет nil и будет проигнорирован.


Ждем Swift 5.0


Внедрение условного соответствия способствует стабильности, а автоматическая поддержка Equatable и Hashable определенно упростит жизнь разработчиков.


Другие предложения сейчас находятся либо на ревью, либо в разработке, в том числе: SE-0192: Non-Exhaustive Enums, SE-0194: Derived Collection of Enum Cases и SE-0195: Dynamic Member Lookup.


Не менее важно, что в этом году Apple, как мы надеемся, выпустят стабилизацию ABI для Swift, и это будет здорово. Ждем-с.

Tags:
Hubs:
+1
Comments 7
Comments Comments 7

Articles