这个通用的合并不应该需要知道,这个特殊的字典里包含一个“列表值对象'财产。
相反,为了让你的函数访问字典的值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
功能将通过(通过使用inout
)伪参考第一个值,随着第二个值,允许您在调用函数时改变第一个值。
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)}
虽然这只是真正意义,如果你的组合逻辑在每次调用函数,我怀疑是不是自己在做什么都会改变。
如果您希望合并逻辑保持不变,那么使用协议可以更好地完成此操作。使用闭包时,每次要调用函数时都必须传入合并逻辑。使用协议,您只需定义一次该逻辑 - 并在需要时调用它。
谢谢!是否有更多的功能编程方法呢?使用闭包?这就是我想要遵循的,而不是基于协议的方法。 (不想开始混合我的代码中的范例...) – Daniel
@Daniel我已经更新了我的答案,显示了如何以这种方式进行操作,尽管IMO协议是更好的方法。使用闭包,每次调用函数时都必须传递自定义逻辑,这并不理想。协议允许你定义这个逻辑一次,并在需要时调用它。 – Hamish
很好的答案,谢谢!一个问题 - 当你在函数式编程解决方案中调用merge()时,为什么你需要做“var returnValue = $ 0”? – Daniel