多数のメンバを持つタイプのメンバへのアクセスを抽象化(汎用化)した下記のsortBy関数は、KeyPathで実現されています。時にはname, 時にはageで配列をソートしたい場合にsortBy関数がどちらの場合でも利用できます。なお、People型のInt型プロパティへのKeyPath<T, V>は\People.ageと表記されます。
class Person {
var name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
func sortBy<T, V: Comparable>(_ keyPath: KeyPath<T, V>, _ array: [T]) -> [T] {
array.sorted { $0[keyPath: keyPath] < $1[keyPath: keyPath] }
}
let p = [Person(name: "A", age: 30), Person(name: "B", age: 25)]
let sorted = sortBy(\Person.age, p)
sorted.forEach { e in
print(e.age) // 25, 30
}
プロパティへのアクセスを変数に格納し、subscript(keyPath:)メソッドで取り出すのであればさほど便利さは無い。
let people = [Person(name: "Alice", age: 25), Person(name: "Bob", age: 30)]
let keyPathToAge = \Person.age
// すべての年齢を取得
let ages = people.map { $0[keyPath: keyPathToAge] }
print(ages) // => [25, 30]
次のコードと同じであり、KeyPathを使った事で記述量が減るわけでも、簡潔な記述となる訳でもない。
let ages = people.map { e in e.age }
次のようにKeyPathを引数に取る関数を作れるところにメリットがある。
func extract<T>(from people: [Person], using keyPath: KeyPath<Person, T>) -> [T] {
return people.map { $0[keyPath: keyPath] }
}
let names = extract(from: people, using: \Person.name)
let ages = extract(from: people, using: \Person.age)
print(names) // => ["Alice", "Bob"]
print(ages) // => [25, 30]