使用JSONEncoder实现Swift中的Equatable方法



我知道JSON键没有任何顺序,可以随机生成,但没有任何东西阻止我编写这个函数,从我的测试来看,它适用于我测试的每个用例。

func ==<T: Encodable> (lhs: T, rhs: T) -> Bool {
let encoder = JSONEncoder()
do {
let leftEncoded = try encoder.encode(lhs)
let rightEncoded = try encoder.encode(rhs)
return leftEncoded == rightEncoded
} catch {
return false
}
}

我想解决的问题是为一个类型编写一个函数,该类型有一个由一个协议组成的数组,有大约20种不同的实现方式,我必须实现==函数,而不是快速自动合成。我知道我可以通过选项.sortedKeys切换到JSONSerialization.writeJSONObject来保持密钥顺序。

与编写==函数的任何其他方法相比,此实现的缺点是什么?

答案似乎就在你的问题中:"JSON键没有任何顺序。"此外,逻辑上相等的两个东西可能会编码不同(例如,如果它们的相等性仅取决于它们的id(。此外,对相同值进行编码的引用类型可能根本不相等(例如UIView(。此外,这会创建一个非常广泛的==重载,使类型检查更加昂贵(就像+非常昂贵一样(。

Equatable可以合成时,你正在做的是尝试自动符合它。斯威夫特本可以做到这一点;事实上,对于大多数Encodable情况,只需添加: Equatable就可以合成Equatable。Swift团队明确选择在这些情况下不自动符合,并强迫你在认真的时候请求它,因为这并不总是意味着"所有属性都包含相同的位"。当Swift团队明显选择避免某个功能时,重新添加它很少是个好主意。

func ==<T: Codable> (lhs: T, rhs: T) -> Bool {
let encoder = JSONEncoder()
guard let lhsData = try? encoder.encode(lhs),
let rhsData = try? encoder.encode(lhs),
let left = try? JSONSerialization.jsonObject(with: lhsData) as? [String : Any],
let right = try? JSONSerialization.jsonObject(with: rhsData) as? [String : Any] else { return false }
let leftDictionary = left as NSDictionary
let rightDictionary = right
return leftDictionary.isEqual(to: rightDictionary)
}

相关内容

最新更新