2016-03-07 37 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