如何创build可以容纳任何东西的字典? 或者它能够容纳的所有可能的types

我想创build一个不限制密钥types的NSDictionary (如NSDictionary

所以我试了

 var dict = Dictionary<Any, Int>() 

 var dict = Dictionary<AnyObject, Int>() 

造成

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

好的,我会用Hashable

 var dict = Dictionary<Hashable, Int>() 

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

所以HashableHashableinheritance,但不符合Equatable ? 我不明白…

无论如何,继续尝试

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

没有运气

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

我现在很迷茫,我怎样才能使编译器满意我的代码?


我想用像这样的字典

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

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

Swift 3更新

你现在可以使用AnyHashable这是一个types擦除哈希值,正是为这样的情景创build的:

var dict = Dictionary<AnyHashable, Int>()

我相信,从Swift 1.2开始,你可以使用一个ObjectIdentifier结构体。 它实现了Hashable(以及Equatable)以及Comparable。 你可以用它来包装任何类的实例。 我猜测实现使用包装对象的底层地址的哈希值,以及在==运算符。

我在苹果开发者论坛的另一篇post中自由地交叉发布/链接到这个问题,这个问题在这里得到了回答 。

编辑

以上链接的答案在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) } 

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

您不能创buildDictionary<Any, Int>()Dictionary<AnyObject, Int>() ,因为AnyAnyObject不能保证这样的Key符合Hashable

你不能创buildDictionary<Hashable, Int>() ,因为Hashable不是一个types,它只是描述所需types的协议。

所以Hashable从Equatableinheritance,但不符合Equatable? 我不明白…

但是你的术语是错误的。 原来的错误是

type 'Hashable' does not conform to inherited protocol 'Equatable.Protocol'这意味着Xcode假定'Hashable'为某种types,但是没有这样的types。 而Xcode把它当作某种空types,显然不符合任何协议(在这种情况下它不符合inheritance协议Equatable

KeyType发生类似的事情。

types别名声明将现有types的命名别名引入到程序中。

你看到existing typeprotocol<Hashable, Equatable>不是一个types,它是协议,所以Xcode再次告诉你, type 'KeyType' does not conform to protocol 'Equatable'

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

Swift是强大的键入语言,你不能做一些事情,比如creating Dictionary that can hold anything in Key 。 实际上字典已经支持任何可以容纳Key的东西,它符合Hashable 。 但是既然你应该指定特定的类,你不能这样做Swift的本地类,因为在Swift中没有像Objective-C这样的主类,它符合(可以借助扩展)符合Hashable

当然你可以使用一些像chriscobuild议的包装。 但我真的无法想象为什么你需要它。 如果你在Swift中打字的能力很强,那么你就不用担心像Objective-C那样的types转换了

Hashable只是一个协议,所以你不能直接指定它作为Key值的types。 你真正需要的是一种expression“任何typesT的方式,例如T实现Hashable 。这是通过Swift中的types约束来处理的:

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

此代码编译。

AFAIK,你只能在generics函数和类上使用types约束。

这不完全回答这个问题,但帮助了我。

一般的答案是为所有types实现Hashable,但是对于Protocols很难实现,因为Hashable扩展了Equatable和Equatable使用Self,这对协议的使用可能会造成严重的限制。

而是实现Printable,然后执行:

 var dict = [String: Int] dict[key.description] = 3 

描述的实现应该是这样的:

 var description : String { return "<TypeName>[\(<Field1>), \(<Field2>), ...]" } 

不是一个完美的答案,但迄今为止最好的:(

这并没有回答OP的问题,但有点相关,并可能希望在某些情况下使用。 假设你真正想要做的是这样的:

  public var classTypeToClassNumber = [Any.Type : Int]() 

但是Swift告诉你“Type”Any.Type“不符合协议Hashable”。

上面的大部分答案都是关于使用对象实例作为字典键,而不是使用对象的types。 (这是公平的,OP就是这么问的。)霍华德·洛瓦特(Howard Lovatt)的回答使我find了一个可行的解决办法。

 public class ClassNumberVsClassType { public var classTypeToClassNumber = [String : Int]() public init() { classTypeToClassNumber[String(describing: ClassWithStringKey.self)] = 367622 classTypeToClassNumber[String(describing: ClassBasedOnKeyedItemList3.self)] = 367629 classTypeToClassNumber[String(describing: ClassBasedOnKeyedItemList2.self)] = 367626 classTypeToClassNumber[String(describing: ClassWithGuidKey.self)] = 367623 classTypeToClassNumber[String(describing: SimpleStruct.self)] = 367619 classTypeToClassNumber[String(describing: TestData.self)] = 367627 classTypeToClassNumber[String(describing: ETestEnum.self)] = 367617 classTypeToClassNumber[String(describing: ClassBasedOnKeyedItemList0.self)] = 367624 classTypeToClassNumber[String(describing: ClassBasedOnKeyedItemList1.self)] = 367625 classTypeToClassNumber[String(describing: SimpleClass.self)] = 367620 classTypeToClassNumber[String(describing: DerivedClass.self)] = 367621 } public func findClassNumber(_ theType : Any.Type) -> Int { var s = String(describing: theType) if s.hasSuffix(".Type") { s = s.substring(to: s.index(s.endIndex, offsetBy: -5)) // Remove ".Type" } let classNumber = _classTypeToClassNumber[s] return classNumber != nil ? classNumber! : -1 } } 

编辑:

如果涉及的类是在不同的模块中定义的,并且如果忽略模块名称,可能会有类名冲突,那么在构build字典时以及在执行查找时都将“String(reflect:”replace为“String 。

你可以使用类名作为Hashable,例如:

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

请参阅如何在Swift中打印variables的types或类。 如何获得课程名称