I want to create a Dictionary
that does not limit the key type (like NSDictionary
)
So I tried
var dict = Dictionary
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.
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
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.
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)
}
You can now use AnyHashable
which is a type-erased hashable value, created exactly for scenarios like this:
var dict = Dictionary<AnyHashable, Int>()
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.
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.