在 Swift 中将 JSONEncoder 用于 Equatable 方法

Using JSONEncoder for Equatable method in Swift

我知道 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 种不同的实现,我必须实现 == 函数而不是 swift自动合成。而且我知道我可以使用选项 .sortedKeys 切换到 JSONSerialization.writeJSONObject 以保留键顺序。

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

答案似乎在您的问题中:"JSON keys don't have any order."此外,两个逻辑上相等的事物可能编码不同(例如,如果它们的相等性仅取决于它们的 id)。此外,编码相同值的引用类型可能根本不相等(例如 UIView)。此外,这会创建一个非常广泛的 == 重载,使类型检查更加昂贵(就像 + 非常昂贵)。

您正在做的是在可以合成时尝试自动符合 Equatable。 Swift 本来可以做到的;事实上,对于大多数 Encodable 情况,只需添加 : Equatable 即可合成 Equatable。 Swift 团队在这些情况下明确选择不自动符合并强制您在需要时提出要求,因为它并不总是意味着 "all the properties contain the same bits." 当 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)
}