【发布时间】:2016-07-13 04:20:12
【问题描述】:
在 Scala 中,immutable.Map 上的 + (k -> v) 运算符返回一个新的 immutable.Map,其中包含原始内容以及新的键/值对。同样,在 C# 中,ImmutableDictionary.add(k, v) 返回一个新的、更新的 ImmutableDictionary。
然而,在 Swift 中,Dictionary 似乎只有可变的 updateValue(v, forKey: k) 函数和可变的 [k:v] 运算符。
我想也许我可以和flatten() 玩一些把戏,但没有运气:
let updated = [original, [newKey: newValue]].flatten()
了解我
Cannot convert value of type '() -> FlattenCollection<[[String : AnyObject]]>'
to specified type '[String : AnyObject]'
如何从现有的内容创建一个新的、修改后的不可变 Dictionary?
更新:基于this answer's note that Swift dictionaries is value types,以及this answer's mutable version,我想出了以下扩展运算符,但我不是对此感到兴奋——似乎必须有一个更干净的开箱即用替代方案。
func + <K, V>(left: [K:V], right: [K:V]) -> [K:V] {
var union = left
for (k, v) in right {
union[k] = v
}
return union
}
但也许事实(如果我理解正确的话)Swift 字典的不变性是对let 的编译器检查,而不是不同实现类的问题,这意味着这是可以做到的最好的吗?
更新 #2: 如 Jules's answer 中所述,修改未专门优化以在副本之间共享状态的不可变字典(因为 Swift 字典不是)会带来性能问题。对于我当前的用例(AttributedString 属性字典,它往往很小),它仍然可以简化某些值得做的事情,但除非 Swift 实现共享状态不可变字典,否则它可能不是一个好主意一般情况——这是不将其作为内置功能的一个很好的理由。
【问题讨论】:
-
看起来有人正在建立一个图书馆来做到这一点github.com/tLewisII/ImStructures(免责声明:我没有审查它。)
-
Swift 字典的不变性是编译器检查 [...] 不同的实现类 这是错误的。字典被实现为结构,这意味着它们(基本上)通过副本传递。存储在
let变量中的任何结构值都是不可变的,因此您不能在其上调用mutating方法,因为它们会更改值。如果您将字典(任何结构)分配给var变量,它将被复制!然后,您将拥有一个具有新内存位置的不同字典。
标签: swift functional-programming immutability