Swift Key Paths 鍵路徑教學
Key Path (鍵路徑) 是一種在 Swift 中功能的強大特性,它允許我們以「引用的方式」來參考一個屬性,而不是直接讀取它的值。
這聽起來很抽象?簡單來說,可以把它想像成屬性的「指標」或「路徑」。
基礎語法
Key Path 的語法是 \Type.Property (反斜線 + 型別 + 點 + 屬性名)。
struct User {
var name: String
var age: Int
}
let user = User(name: "Mike", age: 25)
// 傳統存取
print(user.name) // "Mike"
// 使用 Key Path 存取
let path = \User.name // 這只是一個路徑,還沒取值
print(user[keyPath: path]) // "Mike"
我們使用 subscript(keyPath:) 來透過 Key Path 讀取或寫入值。
Key Path 的種類
根據屬性的特性 (可讀、可寫),Key Path 分為幾種型別:
KeyPath<Root, Value>:唯讀 (Read-only)。例如let屬性。WritableKeyPath<Root, Value>:可讀寫 (Read-write)。例如var屬性 (對 Value Type)。ReferenceWritableKeyPath<Root, Value>:參考可讀寫。用於 Class (Reference Type)。
let namePath: WritableKeyPath<User, String> = \User.name
var user = User(name: "Mike", age: 25)
user[keyPath: namePath] = "John" // 修改值
print(user.name) // "John"
常見應用場景
你可能覺得:「那我直接寫 user.name 就好了,幹嘛這麼麻煩?」
Key Path 的威力在於從資料中抽離出邏輯,特別是在高階函式中。
1. 陣列操作 (Map, Filter, Sort)
Swift 的許多高階函式都支援直接傳入 Key Path。
struct Person {
let name: String
let age: Int
}
let people = [
Person(name: "Alice", age: 30),
Person(name: "Bob", age: 20),
Person(name: "Charlie", age: 25)
]
// 傳統寫法
let names1 = people.map { $0.name }
// Key Path 寫法 (更簡潔)
let names2 = people.map(\.name)
// 排序
let sortedPeople = people.sorted(using: KeyPathComparator(\.age))
2. 通用型設定函式
我們可以利用 Key Path 寫出非常通用的 helper function。
// 一個通用的設定器
func configure<T>(_ subject: inout T, path: WritableKeyPath<T, Int>, value: Int) {
subject[keyPath: path] = value
}
var user = User(name: "Test", age: 0)
configure(&user, path: \.age, value: 18)
3. Identifiable
在 SwiftUI 的 List 或 ForEach 中,我們常需指定 id。這其實就是傳入一個 Key Path。
// \.self 就是一個指向自己的 Key Path
List(items, id: \.self) { item in
Text(item)
}
// 或是指向屬性
List(users, id: \.id) { user in
Text(user.name)
}
總結
- Key Path 是屬性的引用,語法為
\Type.Property。 - 使用
instance[keyPath: path]來存取值。 - 在
map,filter,sorted等高階函式中使用 Key Path 可以讓程式碼更簡潔優雅。