假设我有一枚结构硬币
struct Coin {
var value: Float?
var country: String?
var color: String?
}
我有两个硬币的例子,我们称之为coin a和coinb。
let coinA = Coin()
coinA.value = nil
coinA.country = "USA"
coinA.color = "silver"
let coinB = Coin()
coinB.value = 50.0
现在,我想把coinb的值合并到coina中。因此结果将是coina,其值将导致:
country = "USA"
color = "silver"
value = 50.0
我可以使用merge()函数通过dictionary对象来实现这一点。但是,我不确定如何使用自定义swift对象来实现这一点。有办法吗?
更新
下面是我如何让它与字典一起工作的:
var originalDict = ["A": 1, "B": 2]
var newDict = ["B": 69, "C": 3]
originalDict.merge(newDict) { (_, new) in new }
//originalDict = ["A": 1, "B": 69, "C": 3]
我将进一步澄清,在这个函数中,如果newdict没有originaldict的密钥,originaldict维护它们。
最佳答案
归根结底,在最少的代码行中,最有效的方法可能正是您所期望的:
extension Coin{
func merge(with: Coin) -> Coin{
var new = Coin()
new.value = value ?? with.value
new.country = country ?? with.country
new.color = color ?? with.color
return new
}
}
let coinC = coinA.merge(with: coinB)
注意,在上面的场景中,结果值将始终是
coinA
,并且只有在给定键的coinB
值为coinA
时才会是nil
。无论何时更改、添加或删除Coin
上的属性,也必须更新此方法。但是,如果您更关心将来防止属性更改的方法,而不太关心编写更多的代码和将数据转换成不同的类型,那么您可以在Codable
中获得一些乐趣:struct Coin: Codable{
var value: Float?
var country: String?
var color: String?
func merge(with: Coin, uniquingKeysWith conflictResolver: (Any, Any) throws -> Any) -> Coin{
let encoder = JSONEncoder()
let selfData = try! encoder.encode(self)
let withData = try! encoder.encode(with)
var selfDict = try! JSONSerialization.jsonObject(with: selfData) as! [String: Any]
let withDict = try! JSONSerialization.jsonObject(with: withData) as! [String: Any]
try! selfDict.merge(withDict, uniquingKeysWith: conflictResolver)
let final = try! JSONSerialization.data(withJSONObject: selfDict)
return try! JSONDecoder().decode(Coin.self, from: final)
}
}
有了这个解决方案,您可以像调用任何字典一样在
merge
上调用struct
,不过请注意,它将返回一个新的Coin
实例,而不是对当前实例进行变异:let coinC = coinA.merge(with: coinB) { (_, b) in b}