Ios 使用泛型将两个泛型数组放入一个Swift字典

Ios 使用泛型将两个泛型数组放入一个Swift字典,ios,swift,macos,Ios,Swift,Macos,我试图将两种不同的泛型类型放入一个集合中。在本例中,有两个数组,一个包含Ints,另一个包含Strings let intArray = Array<Int>() let stringArray = Array<String>() let dict = [1:intArray, "one": stringArray] 这导致了两个错误 不支持将“Hashable”用作符合协议“Hashable”的具体类型。 协议“Hashable”只能用作一般约束,因为它具有自身或关

我试图将两种不同的泛型类型放入一个集合中。在本例中,有两个数组,一个包含
Int
s,另一个包含
String
s

let intArray = Array<Int>()
let stringArray = Array<String>()
let dict = [1:intArray, "one": stringArray]
这导致了两个错误

  • 不支持将“Hashable”用作符合协议“Hashable”的具体类型。
  • 协议“Hashable”只能用作一般约束,因为它具有自身或关联的类型要求
添加
import Foundation
并使用
NSDictionary
作为类型工作正常

let dict: NSDictionary = [1:intArray, "one": stringArray]
但是,在不使用基础的情况下,这也应该是在纯SWIFT中的。
词典
的类型是什么

编辑:这显然和键的类型有更多的关系。它们必须是相同的类型,而不仅仅符合Hashable

let dict: [Int:Any] = [1:intArray, 2: stringArray]
这很有效。但有可能使值的类型更精确吗<代码>[Int:Array]不起作用

字典的类型是什么

你可以尝试:

let dict: [NSObject: Any] = [1: intArray, "one": stringArray]

语句
let dict:[Hashable:Any]=…
未编译,因为
字典的键类型必须是符合
Hashable
的具体类型,例如
Int
String
等。
Hashable
不是具体类型

上述建议有效,因为1
NSObject
是一种具体类型(您可以从中实例化对象),2
NSObject
是一个可散列的
3。因为
NSObjects
的子类的实例在这里也可以工作,4。编译器可以从字符串和数字文本初始化
NSObject
子类


如果您不喜欢
NSObject
作为键的类型,您可以创建自己的类或结构。

请注意,您的第一次尝试
让dict=[1:intArray,“one”:stringArray]
在包含
Foundation
的情况下有效;生成一个
NSDictionary
(因此无需显式声明此类型)

<> p>为什么在使用<代码>基金会<代码>时,可以使用这些类型的、显然的、通用的字典,是编译器在将快速的本地类型桥接到基础时执行的(在引擎盖后面)的隐式类型转换。
let intArray : [Int] = [10, 20, 30]
let stringArray : [String] = ["foo", "baz", "bar"]
let dict = [1:intArray, "onx": stringArray]

print(dict.dynamicType)
for e in dict {
    print(e.dynamicType, e.key.dynamicType, e.value.dynamicType)
}

/* __NSDictionaryI
   (AnyObject, AnyObject) __NSCFString _SwiftDeferredNSArray
   (AnyObject, AnyObject) __NSCFNumber _SwiftDeferredNSArray */
上面的
dict
中的键和值被包装在类型
AnyObject
中;只能保存引用(类)类型的对象;值类型<代码> int <代码> >代码>字符串< /代码>为基础引用类型<代码>这仍然是一本
NSDictionary
;e、 g.
AnyObject
本身不符合
Hashable
,因此它不能用作本机Swift字典中的键


如果您希望创建Swift本机“通用密钥”词典,我建议您创建一个符合
Hashable
的包装器(比如一个结构),并包装底层(各种)密钥类型。参见例如(有点过时的)螺纹

详细介绍了@RobNapier的方法,这里有一种类似的方法,它使用
enum
来处理字典的键和值:

enum Key: Equatable, Hashable {
    case IntKey(Int)
    case StringKey(String)

    var hashValue: Int {
        switch self {
        case .IntKey(let value)     : return 0.hashValue ^ value.hashValue
        case .StringKey(let value)  : return 1.hashValue ^ value.hashValue
        }
    }

    init(_ value: Int)    { self = .IntKey(value) }
    init(_ value: String) { self = .StringKey(value) }
}

func == (lhs: Key, rhs: Key) -> Bool {
    switch (lhs, rhs) {
    case (.IntKey(let lhsValue),    .IntKey(let rhsValue))    : return lhsValue == rhsValue
    case (.StringKey(let lhsValue), .StringKey(let rhsValue)) : return lhsValue == rhsValue
    default: return false
    }
}

enum Value {
    case IntValue(Int)
    case StringValue(String)

    init(_ value: Int)    { self = .IntValue(value) }
    init(_ value: String) { self = .StringValue(value) }
}

var dict = [Key: Value]()

dict[Key(1)] = Value("One")
dict[Key(2)] = Value(2)
dict[Key("Three")] = Value("Three")
dict[Key("Four")] = Value(4)

其根本原因是Hashable符合Equatable,Equatable具有
==(lhs:Self,rhs:Self)
要求,这就是“协议'Hashable'只能用作通用约束,因为它具有自身或关联的类型要求”。此外,您需要
=
来解决哈希冲突,因此,这似乎是编译器的合理抱怨。@AntonBronnikov的可能重复相关(但可能重复)链接线程包括字典中具有相同类型键的泛型值,而这包括值和键,后者(泛型键)是更复杂的部分。然而,我意识到这个threas可能是@dfri的复制品,对不起,你是对的。OP的问题更为广泛。在我的问题中已经提到了使用基础和NS字典。@ OrkoDon主要解释了为什么<代码> NSCORGNOR/<代码>在“快速”本机类型上似乎“一般性”地工作,当它实际上在引擎盖后面执行对引用类型的隐式类型转换时;我的答案的最后一部分(参考)指向了一个现有的线程,用于使用Swift:s native
Dictionary
type解决这个问题。安东尼科夫:不过,他的解决方案巧妙地解决了这个问题,很高兴他能帮助你!
enum Key: Equatable, Hashable {
    case IntKey(Int)
    case StringKey(String)

    var hashValue: Int {
        switch self {
        case .IntKey(let value)     : return 0.hashValue ^ value.hashValue
        case .StringKey(let value)  : return 1.hashValue ^ value.hashValue
        }
    }

    init(_ value: Int)    { self = .IntKey(value) }
    init(_ value: String) { self = .StringKey(value) }
}

func == (lhs: Key, rhs: Key) -> Bool {
    switch (lhs, rhs) {
    case (.IntKey(let lhsValue),    .IntKey(let rhsValue))    : return lhsValue == rhsValue
    case (.StringKey(let lhsValue), .StringKey(let rhsValue)) : return lhsValue == rhsValue
    default: return false
    }
}

enum Value {
    case IntValue(Int)
    case StringValue(String)

    init(_ value: Int)    { self = .IntValue(value) }
    init(_ value: String) { self = .StringValue(value) }
}

var dict = [Key: Value]()

dict[Key(1)] = Value("One")
dict[Key(2)] = Value(2)
dict[Key("Three")] = Value("Three")
dict[Key("Four")] = Value(4)