Этот пост является вольным переводом статьи 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, и это будет здорово. Ждем-с.
JosefDzeranov
Что то слишком мало нововведений.