Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

swift

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>()


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.


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)
}

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