Swift 数组缩减:不能对不可变值使用可变成员

Swift array reduction: cannot use mutating member on immutable value

我有以下代码试图合并数组的冗余元素:

var items : [String] = ["hello", "world", "!", "hello"]

var mutableSet = Set<String>()

items.reduce(mutableSet, combine: { (set: Set<String>, element: String) in
    return set.insert(element)
})

set.insert(element) 给我错误 Cannot use mutating member on immutable value: 'set' is a 'let' constant。出了什么问题,我该如何解决?

在Swift中,集合是值类型。不能修改用 let 声明的值类型变量(函数参数隐含)。此外,您的闭包 returns 什么都没有,因此 reduce 可能不会成功。

我认为 reduce 不是完成这项任务的最佳工具。考虑这个 for 循环:

var set = Set<String>()
for element in items { set.insert(element) }

另一个更简单的选择是使用 unionInPlace 方法:

var set = Set<String>()
set.unionInPlace(items)

也许更好的是,直接从集合中创建集合:

var set = Set<String>(items)

返回的'set'值是一个常量。这一点很重要,因为它是累加器,它代表到目前为止已经累积的值。它不应该在你的关闭中改变。

这是我目前正在进行的一个项目的示例,我想在其中找到所有独特的表演者,跨越许多戏剧演出。请注意我是如何使用 union 的,它不会修改常量值 'performers',而是使用它来产生一个新值。

let uniquePerformers = performances.reduce(Set<Performer>(), { (performers: Set<Performer>, performance) -> Set<Performer> in
    return performers.union(Set(performance.performers))
})

OP 代码的问题在于 reduce 中的累加器是不可变的,因此它不允许您使用变异函数 insert()。

一个简洁的解决方案是在 Set 的扩展中定义一个与 insert() 等效的非变异等效项,称为 inserting(),如下所示。

extension Set {
    //returns a new set with the element inserted
    func inserting(_ element: Element) -> Set<Element> {
        var set = self
        set.insert(element)
        return set
    }
}

现在我们可以这样写reduce

var items : [String] = ["hello", "world", "!", "hello"]

let set = items.reduce(Set<String>()){ accumulator, element in
    accumulator.inserting(element)
}