问题
Dictionary key requires Hashable conformance:
class Test {}
var dictionary = [Test: String]() // Type 'Test' dies not conform to protocol 'Hashable'
class Test: NSObject {}
var dictionary = [Test: String]() // Works
How to get address of pure Swift class instance to use as hashValue?
回答1:
Equality can be implemented as object identity, i.e. a == b iff a and b refer to the same instance of the class, and the hash value can be build from the ObjectIdentifier (which is the same for identical objects, compare e.g. Difference between using ObjectIdentifier() and '===' Operator):
For Swift 4.2 and later:
class Test : Hashable {
static func ==(lhs: Test, rhs: Test) -> Bool {
return lhs === rhs
}
public func hash(into hasher: inout Hasher) {
hasher.combine(ObjectIdentifier(self))
}
}
For Swift 3:
class Test : Hashable {
var hashValue: Int { return ObjectIdentifier(self).hashValue }
}
func ==(lhs: Test, rhs: Test) -> Bool {
return lhs === rhs
}
For Swift 2.3 and earlier, you can use
/// Return an UnsafePointer to the storage used for `object`. There's
/// not much you can do with this other than use it to identify the
/// object
func unsafeAddressOf(object: AnyObject) -> UnsafePointer<Void>
i.e.
class Test : Hashable {
var hashValue: Int { return unsafeAddressOf(self).hashValue }
}
func ==(lhs: Test, rhs: Test) -> Bool {
return lhs === rhs
}
Example:
var dictionary = [Test: String]()
let a = Test()
let b = Test()
dictionary[a] = "A"
print(dictionary[a]) // Optional("A")
print(dictionary[b]) // nil
implement the Equatable protocol.
回答2:
Swift 3
This based on the great code snippet in Martin R's answer with insightful comment from Christopher Swasey
class Test: Hashable, Equatable {
lazy var hashValue: Int = ObjectIdentifier(self).hashValue
static func ==(lhs: Test, rhs: Test) -> Bool {
return lhs === rhs
}
}
var dictionary = [Test: String]()
let a = Test()
let b = Test()
dictionary[a] = "A"
print(dictionary[a]) // Optional("A")
print(dictionary[b]) // nil
回答3:
If you don't want or cannot implement Hashable for some reason it's easy to use an Objective C helper:
(long )getPtr:(SomeType* )ptr { return (long )ptr; }
long maps to Swift Int and can be perfectly used as a Swift Dictionary key on both 32 and 64bit architectures. It was the fastest solution which I found while profiling different approaches, including unsafeAddress. In my case performance was the main criteria.
来源:https://stackoverflow.com/questions/30345700/reference-as-key-in-swift-dictionary