【发布时间】:2019-07-09 04:26:22
【问题描述】:
我需要使自定义结构符合Hashable,以便我可以将其用作字典键类型。不过,挑战在于结构的两个属性可以互换,以便识别唯一的实例。
这里有一个简化的例子来说明问题:
struct MultiplicationQuestion {
let leftOperand: Int
let rightOperand: Int
var answer: Int { return leftOperand * rightOperand }
}
识别唯一MultiplicationQuestion 的两个重要属性是leftOperand 和rightOperand,但它们的顺序无关紧要,因为“1 x 2”与“2 x”本质上是同一个问题1'。 (由于我不会在这里讨论的原因,它们需要作为单独的属性保存。)
我尝试如下定义Hashable 一致性,因为我知道我为== 定义的相等性与内置哈希器将要做什么之间存在冲突:
extension MultiplicationQuestion: Hashable {
static func == (lhs: MultiplicationQuestion, rhs: MultiplicationQuestion) -> Bool {
return (lhs.leftOperand == rhs.leftOperand && lhs.rightOperand == rhs.rightOperand) || (lhs.leftOperand == rhs.rightOperand && lhs.rightOperand == rhs.leftOperand)
}
func hash(into hasher: inout Hasher) {
hasher.combine(leftOperand)
hasher.combine(rightOperand)
}
}
我通过创建两组问题并对它们执行各种操作来对此进行测试:
var oneTimesTables = Set<MultiplicationQuestion>()
var twoTimesTables = Set<MultiplicationQuestion>()
for i in 1...5 {
oneTimesTables.insert( MultiplicationQuestion(leftOperand: 1, rightOperand: i) )
twoTimesTables.insert( MultiplicationQuestion(leftOperand: 2, rightOperand: i) )
}
let commonQuestions = oneTimesTables.intersection(twoTimesTables)
let allQuestions = oneTimesTables.union(twoTimesTables)
希望的结果(一厢情愿)是 commonQuestions 包含一个问题 (1 x 2),而 allQuestions 包含九个问题,已删除重复项。
然而,实际结果是不可预测的。如果我多次运行操场,我会得到不同的结果。大多数时候,commonQuestions.count 是 0,但有时是 1。大多数时候,allQuestions.count 是 10,但有时是 9。(我不确定我在期待什么,但这种不一致是当然是惊喜!)
如何使hash(into:) 方法为属性相同但相反的两个实例生成相同的哈希?
【问题讨论】: