如何创建可以在Key中保存任何内容的Dictionary?或它能够容纳的所有可能的类型

Bry*_*hen 54 swift

我想创建一个Dictionary不限制键类型(如NSDictionary)

所以我试过了

var dict = Dictionary<Any, Int>()
Run Code Online (Sandbox Code Playgroud)

和

var dict = Dictionary<AnyObject, Int>()
Run Code Online (Sandbox Code Playgroud)

造成

error: type 'Any' does not conform to protocol 'Hashable'
var dict = Dictionary<Any, Int>()
           ^
<REPL>:5:12: error: cannot convert the expression's type '<<error type>>' to type '$T1'
var dict = Dictionary<Any, Int>()
           ^~~~~~~~~~~~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)

好的,我会用的 Hashable

var dict = Dictionary<Hashable, Int>()
Run Code Online (Sandbox Code Playgroud)

但

error: type 'Hashable' does not conform to protocol 'Equatable'
var dict = Dictionary<Hashable, Int>()
           ^
Swift.Equatable:2:8: note: '==' requirement refers to 'Self' type
  func ==(lhs: Self, rhs: Self) -> Bool
       ^
Swift.Hashable:1:10: note: type 'Hashable' does not conform to inherited protocol 'Equatable.Protocol'
protocol Hashable : Equatable
         ^
<REPL>:5:12: error: cannot convert the expression's type '<<error type>>' to type '$T1'
var dict = Dictionary<Hashable, Int>()
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)

所以Hashable继承自Equatable但不符合Equatable??? 我不明白......

无论如何,继续努力

typealias KeyType = protocol<Hashable, Equatable> // KeyType is both Hashable and Equatable
var dict = Dictionary<KeyType, Int>() // now you happy?
Run Code Online (Sandbox Code Playgroud)

没有运气

error: type 'KeyType' does not conform to protocol 'Equatable'
var dict = Dictionary<KeyType, Int>()
           ^
Swift.Equatable:2:8: note: '==' requirement refers to 'Self' type
  func ==(lhs: Self, rhs: Self) -> Bool
       ^
Swift.Hashable:1:10: note: type 'KeyType' does not conform to inherited protocol 'Equatable.Protocol'
protocol Hashable : Equatable
         ^
<REPL>:6:12: error: cannot convert the expression's type '<<error type>>' to type '$T1'
var dict = Dictionary<KeyType, Int>()
           ^~~~~~~~~~~~~~~~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)

我现在迷失了,我怎么能让编译器满意我的代码呢?


我想用字典之类的

var dict = Dictionary<Any, Int>()
dict[1] = 2
dict["key"] = 3
dict[SomeEnum.SomeValue] = 4
Run Code Online (Sandbox Code Playgroud)

我知道我可以使用Dictionary<NSObject, Int>,但它并不是我想要的.

Yar*_*neo 58

Swift 3更新

您现在可以使用AnyHashable哪个是类型擦除的hashable值,完全针对这样的场景创建:

var dict = Dictionary<AnyHashable, Int>()

  • 这应该是新接受的答案. (3认同)

jul*_*les 16

我相信,从Swift 1.2开始,您可以使用ObjectIdentifier结构.它实现Hashable(因此Equatable)以及Comparable.您可以使用它来包装任何类实例.我猜测实现使用包装对象的hashValue底层地址,以及==运算符.


Chr*_*ver 11

我冒昧地在Apple Dev论坛的另一篇文章中交叉发布/链接到这个问题,这个问题在这里得到解答.

编辑

以上链接的答案适用于6.1及更高版本:

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)
}
Run Code Online (Sandbox Code Playgroud)


Sil*_*ril 7

字典struct Dictionary<Key : Hashable, Value>... 意味着Value可以是你想要的任何东西,Key可以是你想要的任何类型,但Key必须符合Hashable协议.

您无法创建Dictionary<Any, Int>()或Dictionary<AnyObject, Int>(),因为Any并AnyObject不能保证这样的密钥符合Hashable

你不能创建Dictionary<Hashable, Int>(),因为Hashable它不是一种类型,它只是描述所需类型的协议.

Hashable继承自Equatable,但它不符合Equatable ??? 我不明白......

但你的术语是错的.原始错误是

type 'Hashable' does not conform to inherited protocol 'Equatable.Protocol' 这意味着Xcode假定'Hashable'为某种类型,但没有这种类型.并且Xcode将它视为某种类型的空类型,它显然根本不符合任何协议(在这种情况下它不符合继承的协议Equatable)

类似的事情发生在KeyType.

类型别名声明将现有类型的命名别名引入程序.

你看existing type.protocol<Hashable, Equatable>它不是一种类型的协议,所以Xcode再次告诉你type 'KeyType' does not conform to protocol 'Equatable'

你可以使用Dictionary<NSObject, Int>just,因为NSObject符合Hashable协议.

Swift是强类型语言,你不能做一些像creating Dictionary that can hold anything in Key.实际上字典已经支持任何可以在Key中保存的东西,这符合Hashable.但是因为你应该指定特定的类,你不能为本机的Swift类做这个,因为Swift中没有像Objective-C那样的大师类,它符合空气可以符合(借助扩展)到Hashable

当然你可以使用像chrisco建议的一些包装器.但我真的无法想象你为什么需要它.很高兴你在Swift中有强大的输入,所以你不必像在Objective-C中那样担心类型转换


Bil*_*ill 2

Hashable只是一个协议,因此您不能直接将其指定为Key值的类型。你真正需要的是一种表达“任何类型 T 的方式,使得 T 实现Hashable。这是通过 Swift 中的类型约束来处理的:

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

这段代码可以编译。

AFAIK,您只能对泛型函数和类使用类型约束。