Swift 如何创建可以保存关键字中任何内容的词典?或者它能容纳的所有可能的类型

Swift 如何创建可以保存关键字中任何内容的词典?或者它能容纳的所有可能的类型,swift,Swift,我想创建一个不限制键类型的字典(如NSDictionary) 所以我试过了 var dict = Dictionary<Any, Int>() 但是 不走运 error: type 'KeyType' does not conform to protocol 'Equatable' var dict = Dictionary<KeyType, Int>() ^ Swift.Equatable:2:8: note: '==' requirement

我想创建一个不限制键类型的
字典
(如
NSDictionary

所以我试过了

var dict = Dictionary<Any, Int>()
但是

不走运

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>()
           ^~~~~~~~~~~~~~~~~~~~~~~~~~
错误:类型“KeyType”不符合协议“Equalable”
var dict=字典()
^
Swift.Equatable:2:8:注:“==”需求指的是“自我”类型
func==(左:自,右:自)->Bool
^
Swift.Hashable:1:10:注意:类型“KeyType”不符合继承的协议“equalable.protocol”
协议可散列:可均衡
^
:6:12:错误:无法将表达式的类型“”转换为类型“$T1”
var dict=字典()
^~~~~~~~~~~~~~~~~~~~~~~~~~
我现在迷路了,我怎样才能让编译器满意我的代码呢


我想像这样使用字典

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


我知道我可以使用
字典
,但这并不是我真正想要的

Hashable
只是一个协议,因此不能直接将其指定为
键的类型。您真正需要的是一种表达“任意类型T”的方式,这样T就实现了可散列的

func makeDict<T: Hashable>(arr: T[]) {
  let x = Dictionary<T, Int>()
}
func makeDict(arr:T[]{
设x=Dictionary()
}
这段代码可以编译


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

您可以将类名用作哈希表,例如:

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

查看如何获得类名。

这并不能完全回答问题,但对我有所帮助

一般的答案是为所有类型实现Hashable,但是这对于协议来说可能很困难,因为Hashable扩展了equalatable,equalatable使用Self,这对协议的用途造成了严重的限制

而是实现可打印,然后执行以下操作:

var dict = [String: Int]
dict[key.description] = 3
描述的实现必须类似于:

var description : String {
    return "<TypeName>[\(<Field1>), \(<Field2>), ...]"
}
var说明:字符串{
返回“[\(),\(),…]”
}

这不是一个完美的答案,但却是迄今为止我得到的最好的答案:(

我在苹果开发论坛上的另一篇帖子上自由地交叉发布/链接到这个问题,这个问题是

编辑 上述链接的答案适用于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 AnyKey:Hashable{
私人出租:任何
私有let hashValueFunc:()->Int
私有let equalityFunc:(任意)->Bool
init(u键:T){
底层=键
//使用闭包捕获密钥的hashability和equalability。
//该键共享基础值的散列。
hashValueFunc={key.hashValue}
//该键等于相同基础类型的键,
//其基本价值对我们来说是“==”。
equalityFunc={
如果让其他=$0作为?T{
返回键==其他
}
返回错误
}
}
var hashValue:Int{return hashValueFunc()}
}
func==(x:AnyKey,y:AnyKey)->Bool{
返回x.equalityFunc(y.subground)
}

字典是
结构字典…
这意味着值可以是您想要的任何类型,键可以是您想要的任何类型,但键必须符合
Hashable
协议

您不能创建
Dictionary()
Dictionary()
,因为
Any
AnyObject
不能保证这样的键符合
Hashable

var dict = Dictionary<Hashable, Int>()
您无法创建
Dictionary()
,因为
Hashable
不是一种类型,它只是描述所需类型的协议

所以Hashable继承自Equatable,但它不符合 平等???我不明白

但你们在术语上是错的,最初的错误是

类型“Hashable”不符合继承的协议“equalable.protocol”
这意味着Xcode假设“Hashable”是某种类型,但没有这种类型。Xcode将其视为某种空类型,这显然不符合任何协议(在这种情况下,它不符合继承的协议
equalable

类似的情况也发生在
KeyType

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

您可以看到,
现有类型
协议
不是一种类型,它是协议,因此Xcode再次告诉您,
类型“KeyType”不符合协议“equalable”

您可以只使用
字典
,因为
NSObject
符合
Hashable
协议

Swift是一种强大的键入语言,您不能做一些事情,比如创建可以在键中保存任何内容的字典。
。实际上,字典已经支持任何可以在键中保存任何内容的字典,这符合
Hashable
。但由于您应该指定特定的类,所以不能对本机Swift类执行此操作,因为没有Swift中的uch主类与Objective-C中的类似,它符合air的要求,可以(借助扩展)符合
Hashable

var dict = Dictionary<Hashable, Int>()

当然,您可以使用一些包装器,如建议的
chrisco
。但我真的无法想象您为什么需要它。您在Swift中具有强大的键入功能非常好,因此您不必像在Objective-C中那样担心类型转换。我相信,从Swift 1.2开始,您可以使用ObjectIdentifier结构。它实现了Hashable(因此是可等式的)和可比较的。您可以使用它来包装任何类实例。我猜实现使用包装对象的基础地址作为hashValue,以及==运算符。

Swift 3 update 您现在可以使用
AnyHashable
,这是一个类型已擦除的可哈希值,完全是为以下情况创建的:


var dict=Dictionary()

这并没有回答OP的问题,但有点奇怪
var dict = [String: Int]
dict[key.description] = 3
var description : String {
    return "<TypeName>[\(<Field1>), \(<Field2>), ...]"
}
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)
}
   public var classTypeToClassNumber = [Any.Type : Int]()
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
   }
}