此通用合并不需要知道此特定字典具有包含“列表”属性的值对象。
相反,为了让您的函数访问字典值的list 属性,您需要告诉编译器这些值具有list 属性。您可以通过创建协议并将扩展限制为仅对具有符合此协议的值的字典进行操作来做到这一点:
// your protocol that defines the list property
protocol ListType {
var list : [AnyObject] { get set }
}
extension Dictionary where Value : ListType {
func merge(withDictionary: Dictionary) -> Dictionary {
var returnDictionary = withDictionary // make a copy of dictionary (a dictionary is a struct in Swift)
for (key, value) in self { // iterate through key value pairs
if let withDictionaryValue = returnDictionary[key] { // if value exists, merge the list properties
returnDictionary[key]!.list = value.list + withDictionaryValue.list
} else {
returnDictionary[key] = value
}
}
return returnDictionary
}
}
然后,您可以直接或通过扩展使您正在使用的值类型符合此协议。
struct Foo : ListType {
var list: [AnyObject]
}
let d = ["foo" : Foo(list: ["foo", "bar", "baz"])]
let d1 = ["foo" : Foo(list: ["qux", "blah", "blue"])]
let r = d.merge(d1) // ["foo": Foo(list: [foo, bar, baz, qux, blah, blue])]
如果您想要更通用的方法,您可以定义一个Mergable 协议,该协议定义了一个方法,其中符合类型可以执行自己的合并逻辑。然后,如果值符合协议,您将更改您的扩展以调用此方法,否则只需合并键值对。
protocol Mergable {
func merge(withOther:Self) -> Self
}
// if values are Mergable (and the key-value pairs exist in both dictionaries), then call their custom logic for merging
extension Dictionary where Value : Mergable {
func merge(withDictionary: Dictionary) -> Dictionary {
var returnDictionary = withDictionary
for (key, value) in self {
if let withDictionaryValue = withDictionary[key] {
returnDictionary[key] = value.merge(withDictionaryValue)
} else {
returnDictionary[key] = value
}
}
return returnDictionary
}
}
// standard merging logic
extension Dictionary {
func merge(withDictionary: Dictionary) -> Dictionary {
var returnDictionary = withDictionary
keys.forEach {returnDictionary[$0] = self[$0]}
return returnDictionary
}
}
然后你可以像这样使你的值类型符合这个协议:
// Foo's custom merging logic
extension Foo : Mergable {
func merge(withOther: Foo) -> Foo {
var merged = self
// merge the list array
merged.list.appendContentsOf(withOther.list)
return merged
}
}
如果您的字典的值为Mergable,那么编译器将支持执行自定义合并逻辑的扩展,因为首选类型更具体的签名。
在回复您关于希望使用闭包执行此操作的评论时,您可以向 merge 函数添加一个闭包参数,该函数将传递对第一个值的伪引用(通过使用 @987654331 @) 以及第二个值,允许您在调用函数时更改第一个值。
extension Dictionary {
func merge(withDictionary: Dictionary, @noescape merge: (value: inout Value, withValue: Value) -> ()) -> Dictionary {
var returnDictionary = withDictionary // make a copy of dictionary (a dictionary is a struct in Swift)
for (key, value) in self { // iterate through key value pairs
if let withDictionaryValue = returnDictionary[key] {
// create mutable copy of the value
var value = value
merge(value:&value, withValue:withDictionaryValue) // invoke closure to write merging changes to the value
returnDictionary[key] = value // assign value
} else {
returnDictionary[key] = value
}
}
return returnDictionary
}
}
// call merge with our own custom merging logic when a given key exists in both dictionaries
let result = dictA.merge(dictB) {$0.list.appendContentsOf($1.list)}
虽然这只有在每次调用函数时合并逻辑都发生变化时才真正有意义,但我怀疑这不是你在做的事情。
如果您希望合并逻辑保持不变,那么最好使用协议来完成。使用闭包,每次要调用函数时都必须传入合并逻辑。使用协议,您只需定义该逻辑一次 - 并在需要时调用它。