【问题标题】:Swift 5.0 "Set" allowing duplicate valuesSwift 5.0“设置”允许重复值
【发布时间】:2019-11-18 14:53:14
【问题描述】:

在 Swift 5.0 Playground 中,我正在尝试对 CGPoint 进行扩展,使其在哈希和相等方面将点视为整数值。

令我惊讶的是,即使在 CGPoint 上覆盖 hash()== 之后,即使两个元素应该碰撞并只保留一个元素,一组 CGPoints 仍然保持与独立点相似的值。您是否需要覆盖 CGPoint 上的其他方法才能按预期工作?

附:可能最好不要在实践中这样做,因为它可能会影响系统,最好提供某种包装器来管理平等。但我想知道为什么这不起作用。

Playground 内容以及执行后给出的结果:

// Extension to treat points as integer values (not reccomended approach)
extension CGPoint : Hashable {
    public func hash(into hasher: inout Hasher) {
                hasher.combine(Int(x))
        hasher.combine(Int(y))
    }

    static public func == (lhs: CGPoint, rhs: CGPoint) -> Bool {
        return Int(lhs.x) == Int(rhs.x) && Int(lhs.y) == Int(rhs.y)
    }
}

var pSet : Set<CGPoint> = []

let p1 = CGPoint.zero
let p2 =  CGPoint(x: 20.1, y: 30)
let p3 =  CGPoint(x:20, y: 30)

pSet.insert(p1) // inserted true
pSet.insert(p2) // inserted true
pSet.insert(p3) // inserted true(!), should be false

p2 == p3 // true

pSet.count // 3(!), should be two
p2.hashValue  // Same as p3
p3.hashValue  // Same as p2

pSet // shows all three values, all points defined, should be two values only

【问题讨论】:

  • 1.你确认你的hash(into:) 被调用了吗? 2.CGPoint 已经符合Equatable,因此您尝试也实现自己的== 函数可能与现有实现冲突。在扩展中做这样的事情是未定义的。
  • 我不确定,但是从 Set 的插入方法的文档中我注意到:“如果集合中不包含 newMember,则返回 (true, newMember)。如果等于 newMember 的元素是已经包含在集合中,该方法返回 (false, oldMember),其中 oldMember 是等于 newMember 的元素。In some cases, oldMember may be distinguishable from newMember by identity comparison or some other means."。我认为最后一个句子已经回答了你的问题。
  • 您的== 方法在将点插入集合时被调用。

标签: swift hash set equality


【解决方案1】:

rmaddy 和 Martin R 发现了问题,但这里给出了答案:Set 不使用您的 == 函数。它使用标准库中定义的== 函数,因为Set 是在标准库中定义的。您可以通过调用 print 来证明这一点是您的 == 函数。当您在Set 中插入一个点时,您会看到您的print 没有运行。

【讨论】:

  • 谢谢,我被我比较 p2 == p3 的行误导了,这导致了对该方法的一些调用,让我认为集合正在使用它。
猜你喜欢
  • 2019-01-31
  • 1970-01-01
  • 2023-04-08
  • 1970-01-01
  • 1970-01-01
  • 2020-01-08
  • 2019-08-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多