考虑以下代码片段,该代码片段创建了两个Foo
结构集合的差异
struct Foo {
let v: String
let other: Int
}
extension Foo: Hashable {
func hash(into hasher: inout Hasher) {
hasher.combine(v)
}
}
extension Foo: CustomStringConvertible {
var description: String {
return v
}
}
var col1 = [
Foo(v: "a", other: 1),
Foo(v: "b", other: 1),
Foo(v: "c", other: 1),
]
var col2 = [
Foo(v: "a", other: 1),
Foo(v: "c", other: 1),
Foo(v: "d", other: 1),
]
let diff = col2.difference(from: col1)
diff.forEach { change in
switch change {
case let .remove(offset, _, _):
print("remove: \(offset)")
case let .insert(offset, _, _):
print("insert: \(offset)")
}
}
这将按预期产生以下print
输出:
remove: 1
insert: 2
现在像这样将other
的{{1}}字段更改为2
col2
由于我仅从var col2 = [
Foo(v: "a", other: 2),
Foo(v: "c", other: 2),
Foo(v: "d", other: 2),
]
中产生一个哈希值,所以我期望得到相同的输出,但是实际上是这样的。
v
我在这里想念什么?
答案 0 :(得分:0)
BidirectionalCollection.difference(from:)
根据两个集合的元素的平等计算两个集合的“差”。由于您没有为==
实现Foo
,因此编译器将合成一个默认实现,并比较所有(存储的)属性。
采用Hashable
协议可以提高性能,但不会影响值的相等性:不同的元素可以具有相同的哈希值。
如果您提供我们自己的Equatable
的实现方式
extension Foo: Equatable {
static func ==(lhs: Foo, rhs: Foo) -> Bool {
return lhs.v == rhs.v
}
}
然后
Foo(v: "a", other: 1) == Foo(v: "a", other: 2) // etc.
并且输出是预期的
remove: 1
insert: 2
或者,使用``BidirectionalCollection.difference(from:by:)`并通过自定义等效测试:
let diff = col2.difference(from: col1, by: { $0.v == $1.v })