【问题标题】:Reference as key in swift dictionary在 swift 字典中作为键引用
【发布时间】:2015-08-01 11:11:18
【问题描述】:

字典键需要Hashable 一致性:

class Test {}
var dictionary = [Test: String]() // Type 'Test' dies not conform to protocol 'Hashable'

class Test: NSObject {}
var dictionary = [Test: String]() // Works

如何获取纯 Swift 类实例的地址以用作hashValue

【问题讨论】:

    标签: swift dictionary key hashtable memory-address


    【解决方案1】:

    平等可以实现为对象标识,即a == b iff ab 指的是同一个类的实例,并且可以从ObjectIdentifier 构建哈希值(这对于相同的对象,比较例如Difference between using ObjectIdentifier() and '===' Operator):

    对于 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 协议。

    【讨论】:

    • unsafeAddressOf 是我一直在寻找的。谢谢!
    • 会有unsafeAddressOf 为同一个变量返回不同地址的情况吗?我似乎遇到了这个问题,并且无法再重现它。地址一开始会说一件事,然后它会改变,就好像 Swift 将内存中的变量移动到别处一样。
    • 不适用于 class 的实例。但请参阅 stackoverflow.com/questions/32638879/… 以了解隐式桥接到某些 NSObject 的某些 值类型 会发生这种情况。
    • 属性声明可以收紧到lazy var hashValue: Int = ObjectIdentifier(self).hashValue
    【解决方案2】:

    斯威夫特 3

    这基于 Martin R's answer 中的出色代码 sn-p 以及来自 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】:

      如果您出于某种原因不想或无法实现 Hashable,则可以轻松使用 Objective C 助手:

      (long )getPtr:(SomeType* )ptr { return (long )ptr; }

      long 映射到 Swift Int 并且可以完美地用作 32 位和 64 位架构上的 Swift Dictionary 键。这是我在分析不同方法时发现的最快的解决方案,包括unsafeAddress。就我而言,表现是主要标准。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-03-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-07-24
        相关资源
        最近更新 更多