2016-03-07 39 views
2

我试图将两个不同的泛型类型放入集合中。在这个例子中有两个阵列,一个包含Ints和另一个Strings。将两个泛型数组合并成一个具有泛型的Swift字典

let intArray = Array<Int>() 
let stringArray = Array<String>() 
let dict = [1:intArray, "one": stringArray] 

错误消息为表达式的类型在没有更多上下文的情况下是不明确的。

所以,我想指定Dictionary的类型

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

这导致了两个错误。

  • 不支持使用'Hashable'作为符合协议'Hashable'的具体类型。
  • 协议“哈希的”只能作为一种通用的约束,因为它具有自我或相关类型的要求

添加import Foundation和使用NSDictionary作为类型工作正常。

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

但是,在没有使用Foundation的情况下,这在纯Swift中也应该是可能的。 Dictionary必须有什么类型?

编辑:这显然有更多的与键的类型。他们必须是相同的类型,不仅符合Hashable

let dict: [Int:Any] = [1:intArray, 2: stringArray] 

This works。但是是否有可能使价值的类型更加精确? [Int:Array<Any>]不起作用。

+1

这样做的根本原因是Hashable符合Equatable,而Equatable具有'==(lhs:Self,rhs:Self)'要求,这就是'Protocol'Hashable'后面的要求,因为它只能用作通用约束,因为它具有自我或相关类型要求“。 – BallpointBen

+0

另外,你需要'=='来解决散列冲突,所以这似乎是编译器的有效投诉。 – BallpointBen

+1

[Swift中的通用字典值类型]的可能重复(http://stackoverflow.com/questions/24736612/generic-dictionary-value-type-in​​-swift) – courteouselk

回答

1

在阐述了answer从@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) 
1

该字典必须具有什么类型?

你可以试试:

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

let dict: [Hashable: Any] = ...不能编译的声明,因为Dictionary关键的类型必须具体类型符合Hashable,例如IntStringHashable不是具体类型。

上述建议的工作,因为1. NSObject是一个具体类型(在这里你可以从实例化对象),2 NSObjectHashable,并3.由于NSObjects子类的实例将在这里工作,以及,4 。编译器可以从字符串和数字文字初始化NSObject子类。

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

1

请注意,您的第一次尝试let dict = [1:intArray, "one": stringArray]如果包含Foundation;产生一个NSDictionary(所以不需要明确说明这种类型)。

当使用Foundation时,我们可以拥有这些类型的显然是通用字典的原因是编译器在将Swift本机类型桥接到Foundation时执行的隐式类型转换(在引擎盖后面)。

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类型;它只能容纳引用(类)类型的对象; the compiler implicitly performs conversion价值类型Int/String以基础参考类型__NSCFNumber/__NSCFString。尽管如此,这仍然是一个NSDictionary;例如AnyObject本身不符合Hashable,因此它不能用作本地Swift字典中的密钥。


如果你想创建斯威夫特天然的“通用钥匙”的字典,我建议你创建一个包装符合Hashable和封装在底层(各种)密钥类型(比如结构) (S)。见例如(有些过时)线程

+0

使用基础和NSDictionary已经在我的问题中提到。 – orkoden

+0

@orkoden我主要解释了为什么'NSDictionary'似乎对Swift本机类型“一般”起作用,当它实际上在隐藏引擎后面执行隐式类型转换时引用类型;我的答案的最后一部分(指向[这个答案](http://stackoverflow.com/questions/24119624/))指向一个现有的线程解决这个与Swift:本地'字典'类型。 AntonBronnikov:解决方案很好地解决了这个问题,很高兴他能帮助你! – dfri