假设我有一枚结构硬币

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}

10-08 07:43