0Pricing
Swift Academy · Урок

Основы 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 — локальная установка не требуется.

Все уроки этого курса

  1. Основы KeyPath
  2. Использование KeyPaths в коллекциях
  3. Записываемые и ссылочные KeyPaths
  4. @dynamicMemberLookup
← Назад к Swift Academy