Основы KeyPath
Используйте свойства как значения первого класса.
«Основы KeyPath» — бесплатный урок Swift Academy на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Swift Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Swift Academy содержит 4 уроков всего.
Что такое путь к свойству
Путь к свойству — это значение, описывающее путь к свойству, не обращаясь к нему напрямую. Представьте его как сохранённую повторно используемую ссылку на то, какое свойство Вам нужно, отдельно от того, какой экземпляр Вы читаете.
Путь к свойству записывается с помощью обратной косой черты, имени типа, точки и имени свойства. Swift представляет это выражение как значение KeyPath, с которым можно обращаться как с любым другим значением.
struct Person {
let name: String
let age: Int
}
let nameKeyPath = \Person.name
print(type(of: nameKeyPath))Чтение значения
Чтобы прочитать свойство через путь к свойству, используйте оператор индексации [keyPath:] у экземпляра. Передайте путь к свойству в квадратных скобках, и Swift вернёт значение по этому пути.
Это аналог обращения к имени свойства во время выполнения, но теперь свойство выбирается данными, а не задаётся напрямую в коде.
struct Person {
let name: String
let age: Int
}
let alice = Person(name: "Alice", age: 30)
let path = \Person.name
print(alice[keyPath: path])Синтаксис пути к свойству подробно
Общая форма состоит из экранирования обратной косой чертой, затем корневого типа, точки и имени свойства. Обратная косая черта сообщает Swift, что Вам нужен путь к свойству, а не само значение свойства.
Корневой тип — это тип, от которого начинается путь. Тип результата — это тип конечного свойства. Поэтому путь от Person к его свойству age имеет корневой тип Person и тип значения Int.
struct Person {
let name: String
let age: Int
}
let ageKeyPath: KeyPath<Person, Int> = \Person.age
let bob = Person(name: "Bob", age: 42)
print(bob[keyPath: ageKeyPath])Переход через вложенные свойства
Пути к свойствам могут проходить через вложенные значения. Если свойство само является структурой, Вы можете продолжить путь ещё одной точкой и обратиться к более глубокому свойству.
Вся цепочка по-прежнему является одним значением пути к свойству, а её корневой тип и тип результата соответствуют началу и концу цепочки.
struct Address {
let city: String
}
struct Person {
let name: String
let address: Address
}
let cityPath = \Person.address.city
let carol = Person(name: "Carol", address: Address(city: "Oslo"))
print(carol[keyPath: cityPath])Сохранение путей к свойствам в переменных
Поскольку путь к свойству — это всего лишь значение, его можно сохранить в переменной, вернуть из функции или хранить коллекцию путей к свойствам. Это позволяет выбрать, какое свойство читать, во время выполнения.
Здесь мы выбираем один из двух сохранённых путей к свойствам на основе флага.
struct Person {
let name: String
let age: Int
}
let showAge = true
let chosen: PartialKeyPath<Person> = showAge ? \Person.age : \Person.name
let dave = Person(name: "Dave", age: 27)
print(dave[keyPath: chosen])PartialKeyPath и AnyKeyPath
В Swift есть небольшое семейство типов путей к свойствам. KeyPath<Root, Value> знает оба конца пути. PartialKeyPath<Root> знает корень, но скрывает тип значения. AnyKeyPath скрывает оба типа.
Чем больше информации о типах Вы сохраняете, тем больше проверок за Вас может выполнить компилятор. Используйте частичные или универсальные варианты только тогда, когда действительно нужно объединить пути со значениями разных типов.
struct Person {
let name: String
let age: Int
}
let paths: [PartialKeyPath<Person>] = [\.name, \.age]
let eve = Person(name: "Eve", age: 19)
for p in paths {
print(eve[keyPath: p])
}Сокращённая запись в известном типе
Если корневой тип уже известен из контекста, можно опустить имя типа и записать только обратную косую черту, точку и свойство. Компилятор выведет корневой тип самостоятельно.
Такая сокращённая запись делает места вызова короче, особенно внутри операций над коллекциями, где тип элемента очевиден.
struct Person {
let name: String
let age: Int
}
func value(of person: Person, at path: KeyPath<Person, Int>) -> Int {
person[keyPath: path]
}
let frank = Person(name: "Frank", age: 55)
print(value(of: frank, at: \.age))Пути к свойствам как аргументы функций
Распространённый шаблон — обобщённая функция, принимающая путь к свойству и применяющая его к нескольким экземплярам. Это отделяет то, что Вы читаете, от логики чтения.
Здесь вспомогательная обобщённая функция извлекает любое свойство любого типа из списка людей.
struct Person {
let name: String
let age: Int
}
func extract<T>(_ people: [Person], _ path: KeyPath<Person, T>) -> [T] {
people.map { $0[keyPath: path] }
}
let people = [Person(name: "Ana", age: 21), Person(name: "Ben", age: 34)]
print(extract(people, \.name))
print(extract(people, \.age))Пути к свойствам и вычисляемые свойства
Пути к свойствам, доступные только для чтения, работают и с вычисляемыми свойствами. Путь сохраняет вычисление, поэтому чтение через него запускает метод чтения.
Это означает, что путь к свойству не ограничен хранимыми свойствами: подойдёт любое свойство, доступное для чтения.
struct Rectangle {
let width: Double
let height: Double
var area: Double { width * height }
}
let areaPath = \Rectangle.area
let r = Rectangle(width: 3, height: 4)
print(r[keyPath: areaPath])Путь к самому значению
Существует специальный путь к свойству, который ссылается на всё значение целиком. Он записывается как одна обратная косая черта, за которой следуют точка и self. Чтение через него возвращает экземпляр без изменений.
Он удобен, когда программный интерфейс ожидает путь к свойству, а Вам нужен сам элемент, например при сортировке чисел по их собственным значениям.
let numbers = [3, 1, 2]
let identity = \Int.self
for n in numbers {
print(n[keyPath: identity])
}Сравнение путей к свойствам
Пути к свойствам поддерживают Hashable и Equatable. Два пути к свойствам, указывающие на одно свойство одного типа, равны, поэтому их можно хранить во множествах или использовать как ключи словаря.
Это удобно для создания таблиц, сопоставляющих свойство с меткой или средством форматирования.
struct Person {
let name: String
let age: Int
}
let labels: [PartialKeyPath<Person>: String] = [
\Person.name: "Full Name",
\Person.age: "Years Old"
]
print(labels[\Person.age] ?? "unknown")Проверка: чтение через путь к свойству
Проверьте, насколько хорошо Вы поняли чтение свойства через путь к свойству.
Итоги: основы путей к свойствам
Вы изучили основы путей к свойствам:
- Путь к свойству записывается с помощью обратной косой черты, корневого типа, точки и имени свойства и описывает свойство, не читая его.
- Читайте значение с помощью оператора индексации
[keyPath:]у экземпляра. - Пути могут проходить через вложенные свойства и обращаться к вычисляемым свойствам.
KeyPath,PartialKeyPathиAnyKeyPathобеспечивают компромисс между безопасностью типов и гибкостью.- Пути к свойствам являются значениями: сохраняйте их, передавайте, сравнивайте и используйте как ключи словаря.
Далее Вы используете пути к свойствам, чтобы сделать операции над коллекциями значительно короче.
struct Person {
let name: String
let age: Int
}
let path = \Person.age
let gina = Person(name: "Gina", age: 48)
print("Read via key path: \(gina[keyPath: path])")Часто задаваемые вопросы
Урок «Основы KeyPath» бесплатный?
Да — полный текст урока «Основы KeyPath» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Swift Academy, подпишись на CoddyKit PRO. Курс Swift Academy содержит 4 уроков всего.
Чему я научусь в уроке «Основы KeyPath»?
Используйте свойства как значения первого класса. Ты практикуешь Swift Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Swift Academy?
Предыдущий опыт не требуется. Swift Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.
Сколько времени занимает урок «Основы KeyPath»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Swift Academy?
Да. Каждый урок Swift Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Основы KeyPath
- Использование KeyPaths в коллекциях
- Записываемые и ссылочные KeyPaths
- @dynamicMemberLookup