如何在 Swift 4.0 中使用 WritableKeyPath 更新数组

How to update an array with WritableKeyPath in Swift 4.0

在 Swift 4.0 中,我有一个结构数组。有没有一种方法可以使用 keyPaths 更新数组中的所有项目,而无需像 map 或 forEach 那样手动迭代?类似于 objc [people makeObjectsPerformSelector: @selector(setName:) withObject: @"updated"];

struct Person {
    var name: String? = "Empty"
}
var people = [Person(), Person()]

//This only updates one person:
people[keyPath: \[Person].[0].name] = "single update"

//I'm looking to accomplish something like this without a map
let updatedPeople = people.map { (person: Person) -> Person in
    var copy = person
    copy[keyPath: \Person.name] = "updated"
    return copy
}

有点像 人[keyPath: \[People].all.name] = "update all without manually iterating"

变异为数组成员需要左值。 Swift 的 l-values 机制是下标,所以我们可以使用它:

for i in people.indices {
    people[i][keyPath: \Person.name] = updated
    // or more simply, just:
    // people[i].name = "updated"

    // This even works too, but I can't see any reason why it would be desirable
    // over the other 2 approaches:
    // people[keyPath: \[Person].[i].name] = "update"
}

你也可以使用 forEach,但我通常只建议在你有一个现有的 closure/function 要传递的类型为 (Index) -> Void 的情况下超过 for :

// meh
people.indices.forEach {
    people[[=11=]][keyPath: \Person.name] = "updated"
}

EDIT 回答你现在编辑的问题,询问 Swift 等同于 [people makeObjectsPerformSelector: @selector(setName:) withObject: @"updated"],简单的答案是 map,您出于某种原因拒绝了您的问题, 等价物。当然,要实现 Objective-C 的功能,我们必须使用对象类型的 Objective-C 样式,即 class:

class Person {
    var name: String? = "Empty"
}
var people = [Person(), Person()]
people = people.map {[=10=].name = "updated"; return [=10=]} // *

带星号的行如何使数组中的对象执行"selector"。

结构是一种值类型,所以正如您在问题中所说的那样,我们必须插入一个带有 var 引用的临时变量:

struct Person {
    var name: String? = "Empty"
}
var people = [Person(), Person()]
people = people.map {var p = [=11=]; p.name = "updated"; return p}

[原回答:]

您问题中关键路径的使用似乎是在转移注意力。您只是在询问如何设置数组中所有结构的 属性。

map 只是循环遍历数组的一种方式。如果不 循环遍历数组,您就无法神奇地做到这一点;如果您不显式执行,则必须隐式执行。

这是一个明确的方法:

struct Person {
    var name: String? = "Empty"
}
var people = [Person(), Person()]
let kp = \Person.name
for i in 0..<people.count {
    people[i][keyPath:kp] = "updated"
}

据我所知,这实际上并不比使用 map 更有效;结构不是可变的,所以我们仍然用全新的 Person 对象填充数组,就像我们使用 map.

时所做的一样