在 swift 字典中作为键引用
Reference as key in swift dictionary
词典键需要 Hashable
一致性:
class Test {}
var dictionary = [Test: String]() // Type 'Test' dies not conform to protocol 'Hashable'
class Test: NSObject {}
var dictionary = [Test: String]() // Works
如何获取纯 Swift class 实例的地址以用作 hashValue
?
相等性可以实现为对象标识,即a == b
当且仅当a
和b
指的是class的同一个实例,哈希值可以是从 ObjectIdentifier
构建(对于相同的对象是相同的,比较例如 ):
对于 Swift 4.2 及更高版本:
class Test : Hashable {
static func ==(lhs: Test, rhs: Test) -> Bool {
return lhs === rhs
}
public func hash(into hasher: inout Hasher) {
hasher.combine(ObjectIdentifier(self))
}
}
对于Swift 3:
class Test : Hashable {
var hashValue: Int { return ObjectIdentifier(self).hashValue }
}
func ==(lhs: Test, rhs: Test) -> Bool {
return lhs === rhs
}
对于 Swift 2.3 及更早版本,您可以使用
/// 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>
即
class Test : Hashable {
var hashValue: Int { return unsafeAddressOf(self).hashValue }
}
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
实施 Equatable
协议。
如果您出于某种原因不想或不能实施 Hashable
,使用 Objective C 助手很容易:
(long )getPtr:(SomeType* )ptr { return (long )ptr; }
long
映射到 Swift Int
并且可以完美地用作 32 位和 64 位体系结构上的 Swift Dictionary
键。这是我在分析不同方法(包括 unsafeAddress
)时发现的最快的解决方案。在我的案例中,性能是主要标准。
Swift 3
这基于 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
词典键需要 Hashable
一致性:
class Test {}
var dictionary = [Test: String]() // Type 'Test' dies not conform to protocol 'Hashable'
class Test: NSObject {}
var dictionary = [Test: String]() // Works
如何获取纯 Swift class 实例的地址以用作 hashValue
?
相等性可以实现为对象标识,即a == b
当且仅当a
和b
指的是class的同一个实例,哈希值可以是从 ObjectIdentifier
构建(对于相同的对象是相同的,比较例如
对于 Swift 4.2 及更高版本:
class Test : Hashable {
static func ==(lhs: Test, rhs: Test) -> Bool {
return lhs === rhs
}
public func hash(into hasher: inout Hasher) {
hasher.combine(ObjectIdentifier(self))
}
}
对于Swift 3:
class Test : Hashable {
var hashValue: Int { return ObjectIdentifier(self).hashValue }
}
func ==(lhs: Test, rhs: Test) -> Bool {
return lhs === rhs
}
对于 Swift 2.3 及更早版本,您可以使用
/// 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>
即
class Test : Hashable {
var hashValue: Int { return unsafeAddressOf(self).hashValue }
}
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
实施 Equatable
协议。
如果您出于某种原因不想或不能实施 Hashable
,使用 Objective C 助手很容易:
(long )getPtr:(SomeType* )ptr { return (long )ptr; }
long
映射到 Swift Int
并且可以完美地用作 32 位和 64 位体系结构上的 Swift Dictionary
键。这是我在分析不同方法(包括 unsafeAddress
)时发现的最快的解决方案。在我的案例中,性能是主要标准。
Swift 3
这基于
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