我目前的方法是使用其中一个属性的哈希值作为
类的哈希值,以及
== <T> (lhs: ClassA<T>, rhs: ClassA<T>) -> Bool
功能是通过比较哈希值来完成的
== 和 hashValue 关系不是这样工作的——不要这样做。如果遇到哈希冲突怎么办?具有不同属性的两个不同实例可以比较相等。
您应该改为实现== 以实际比较两个实例的属性。如果两个给定实例具有相同的属性,== 应该返回 true。如果两个实例的hashValues 与== 比较相等,则它们应该相等。
现在,除非T 是Equatable,否则您可能无法进行此比较。一种解决方案是不将ClassA 与Equatable 一致,而是在T 为Equatable 时重载==,例如:
func == <T : Equatable>(lhs: ClassA<T>, rhs: ClassA<T>) -> Bool {
// stub: do comparison logic
}
您现在可以将Sequence 的contains(where:) 方法与== 重载结合使用,以检查给定实例是否在数组中:
var array = [ClassA("foo")] // assuming ClassA has an init(_: T) and a suitable ==
// implementation to compare that value
let someInstanceToFind = ClassA("foo")
print(array.contains { $0 == someInstanceToFind }) // true
如果你想让ClassA 有一个hashValue,那么只需编写一个extension,当T 是Hashable 时定义一个hashValue:
extension ClassA where T : Hashable {
var hashValue: Int {
return 0 // to do: implement hashValue logic
}
}
不幸的是,这确实意味着ClassA 不会明确地符合Hashable,而T 确实如此——但它会有hashValue 和== 实现。如果满足给定的where 子句,SE-0143: Conditional conformances 将通过允许显式遵守协议来改变这一点,但这尚未实现。
如果您需要明确符合 Hashable(例如在 Set 或 Dictionary 键中使用类的实例),那么一种解决方案是创建包装器类型:
struct HashableClassA<T : Hashable> : Hashable {
var base: ClassA<T>
init(_ base: ClassA<T>) {
self.base = base
}
static func ==(lhs: HashableClassA, rhs: HashableClassA) -> Bool {
return lhs.base == rhs.base
}
var hashValue: Int {
return base.hashValue
}
}
现在您只需将ClassA<T> 实例包装在HashableClassA 实例中,然后再添加到Set 或Dictionary。