我想更好地理解 SWIFT Keypaths,特别是:
- 创建包含多个级别的键路径
- 创建下标到数组中的键路径
- 将密钥路径连接在一起
- 了解键路径的类型
让我们从这些结构开始:
struct Pet {
var name: String
}
struct Address {
var postcode: String
}
struct Person {
var name: String
var age: Int
var address: Address
var possessions: [String]
var pets: [Pet]
}
以及这些变量:
let john = Person(
name: "John",
age: 50,
address: Address(postcode: "BS1 9ZZ"),
possessions: [ "Book",
"Laptop" ],
pets: [ Pet(name: "Linga"),
Pet(name: "Pharaoh") ]
)
let addresses: [Address] = [ Address(postcode: "ABC"),
Address(postcode: "DEF") ]
1( 创建包含多个级别的键路径
print("Field")
print(john[keyPath: Person.name]) // John
print(john[keyPath: Person.possessions]) // ["Book", "Laptop"]
print("Nested fields")
print(john[keyPath: Person.address.postcode]) // BS1 9ZZ
2( 创建下标为数组的键路径
print("Array lookup")
print(addresses[keyPath: [Address][1] ]) // Address(postcode: "DEF")
print("Multilevel with array")
print(john[keyPath: Person.possessions[1]]) // Laptop
print(john[keyPath: Person.pets[0].name]) // Linga
print("Multilevel using normal indexing")
print(john[keyPath: Person.possessions][1]) // Laptop
print(john[keyPath: Person.pets][0][keyPath: Pet.name]) // Linga
3( 将密钥路径连接在一起
print("Join keypaths")
let kp1: KeyPath<Person, Address> = Person.address
let kp2: KeyPath<Address, String> = Address.postcode
let kpboth = kp1.appending(path: kp2)
print(john[keyPath: kpboth])
print("Join keypaths including array")
let kpa = Person.pets
let kpb = [Pet][0]
let kpc = Pet.name
let kpall = kpa.appending(path: kpb).appending(path: kpc)
print(john[keyPath: kpall]) // Linga
print("Join keypaths inline")
print(john[keyPath: (Person.pets).appending(path: ([Pet][0])).appending(path: (Pet.name))]) // Linga
4( 了解键路径的类型
密钥路径的类型为:
KeyPath<FromType, ToType>
其中 FromType 是输入类型,ToType 是输出类型。
所以键路径的类型:\Person.pets 是
KeyPath<Person, [Pet]>
因为这从一个人开始,找到一系列宠物。
类似地,KeyPath: [Pet][0] 的类型为:
KeyPath<[Pet],Pet>
因为这从一系列宠物开始并找到宠物。
联接键路径时,左侧键路径的输出类型必须与右侧键路径的输入类型匹配。 如果我们重复前面的示例但显示显式类型,我们可以清楚地看到这一点:
print("Join keypaths including array with Explicit Types")
let kpA: KeyPath<Person, [Pet] > = Person.pets
let kpB: KeyPath<[Pet], Pet > = [Pet][0]
let kpC: KeyPath<Pet, String> = Pet.name
let kpALL = kpA.appending(path: kpB).appending(path: kpC)
print(john[keyPath: kpALL]) // Linga