How to create Dictionary that can hold anything in Key? or all the possible type it capable to hold

前端 未结 8 2039
感动是毒
感动是毒 2020-12-05 04:13

I want to create a Dictionary that does not limit the key type (like NSDictionary)

So I tried

var dict = Dictionary

        
相关标签:
8条回答
  • 2020-12-05 04:24

    I believe that, as of Swift 1.2, you can use an ObjectIdentifier struct for this. It implements Hashable (and hence Equatable) as well as Comparable. You can use it to wrap any class instance. I'm guessing the implementation uses the wrapped object's underlying address for the hashValue, as well as within the == operator.

    0 讨论(0)
  • 2020-12-05 04:25

    Dictionary is struct Dictionary<Key : Hashable, Value>... Which means that Value could be anything you want, and Key could be any type you want, but Key must conform to Hashable protocol.

    You can't create Dictionary<Any, Int>() or Dictionary<AnyObject, Int>(), because Any and AnyObject can't guarantee that such a Key conforms Hashable

    You can't create Dictionary<Hashable, Int>(), because Hashable is not a type it is just protocol which is describing needed type.

    So Hashable inherited from Equatable but it does not conform to Equatable??? I don't understand...

    But you are wrong in terminology. Original error is

    type 'Hashable' does not conform to inherited protocol 'Equatable.Protocol' That means that Xcode assuming 'Hashable' as some type, but there is no such type. And Xcode treat it as some kind empty type, which obviously does not conform any protocol at all (in this case it does not conform to inherited protocol Equatable)

    Something similar happens with KeyType.

    A type alias declaration introduces a named alias of an existing type into your program.

    You see existing type. protocol<Hashable, Equatable> is not a type it is protocol so Xcode again tells you that type 'KeyType' does not conform to protocol 'Equatable'

    You can use Dictionary<NSObject, Int> just, because NSObject conforms Hashable protocol.

    Swift is strong typing language and you can't do some things like creating Dictionary that can hold anything in Key. Actually dictionary already supports any can hold anything in Key, which conforms Hashable. But since you should specify particular class you can't do this for native Swift classes, because there is no such master class in Swift like in Objective-C, which conforms air could conform (with a help of extensions) to Hashable

    Of course you can use some wrapper like chrisco suggested. But I really can't imagine why you need it. It is great that you have strong typing in Swift so you don't need to worry about types casting as you did in Objective-C

    0 讨论(0)
  • 2020-12-05 04:27

    I took the liberty of cross-posting / linking to this question on a separate post on the Apple Dev forums and this question is answered here.

    Edit

    This answer from the above link works in 6.1 and greater:

    struct AnyKey: Hashable {
        private let underlying: Any
        private let hashValueFunc: () -> Int
        private let equalityFunc: (Any) -> Bool
    
        init<T: Hashable>(_ key: T) {
            underlying = key
            // Capture the key's hashability and equatability using closures.
            // The Key shares the hash of the underlying value.
            hashValueFunc = { key.hashValue }
    
            // The Key is equal to a Key of the same underlying type,
            // whose underlying value is "==" to ours.
            equalityFunc = {
                if let other = $0 as? T {
                    return key == other
                }
                return false
            }
        }
    
        var hashValue: Int { return hashValueFunc() }
    }
    
    func ==(x: AnyKey, y: AnyKey) -> Bool {
        return x.equalityFunc(y.underlying)
    }
    
    0 讨论(0)
  • 2020-12-05 04:30

    Swift 3 update

    You can now use AnyHashable which is a type-erased hashable value, created exactly for scenarios like this:

    var dict = Dictionary<AnyHashable, Int>()

    0 讨论(0)
  • 2020-12-05 04:30

    You can use the class name as a Hashable, e.g.:

    var dict = [String: Int]
    dict[object_getClassName("key")] = 3
    

    See How do I print the type or class of a variable in Swift? for how you might get the class name.

    0 讨论(0)
  • 2020-12-05 04:31

    Hashable is just a protocol so you can't specify it directly as a type for the Key value. What you really need is a way of expressing "any type T, such that T implements Hashable. This is handled by type constraints in Swift:

    func makeDict<T: Hashable>(arr: T[]) {
      let x = Dictionary<T, Int>()
    }
    

    This code compiles.

    AFAIK, you can only use type constraints on generic functions and classes.

    0 讨论(0)
提交回复
热议问题