2014-09-22 24 views
6

推斷類型我有一個數組轉換爲一個字典一個看似合法的功能:斯威夫特不能從上下文

func arrayToDictionary<Key : Hashable, Value> 
    (source: Array<Value>, key: Value -> Key) -> Dictionary<Key, Value> { 
    var dictionary = Dictionary<Key, Value>() 
    for element in source { 
    let key = key(element) 
    dictionary[key] = element 
    } 
    return dictionary 
} 

現在,當我試圖把它叫做:

let dict = arrayToDictionary([1, 2, 3], { val in return val }) 

我得到一個錯誤 - 不能轉換表達式的類型'($ T6,(($ T9) - >($ T9) - > $ T8) - >((T9) - > $ T8) - > $ T8)

奇怪的是,如果我使用隱式返回:

let dict = arrayToDictionary([1, 2, 3], { val in val }) 

或簡寫:

let dict = arrayToDictionary([1, 2, 3], { $0 }) 

它工作得很好。爲什麼?

+0

'讓字典= arrayToDictionary([1,2,3],{在VAL VAL})'(拿出'返回)也似乎工作得很好。 – 2014-09-22 18:14:02

+0

而且,甚至是陌生人,用'return'將'val'明確地定義爲'Int':'let dict = arrayToDictionary([1,2,3],{(val:Int)in return val})'導致錯誤:''NSNumber'不是'Int''的子類型。再次返回'返回'仍然有效。 – 2014-09-22 18:21:58

+0

這看起來像一個編譯器bug,我建議你報告它。一些優化在幕後進行得太早,並且類型檢查器不會很高興 – 2014-10-01 09:59:21

回答

2

這個問題只能由Apple的編譯器工程師真正回答,根據上述評論者的說法,它可能/應該被認爲是一個錯誤,但這絕對是他們簡寫語法中的一個漏洞。對於這樣的問題,我從發佈到devforums獲得了很好的結果。

但是,一個簡單的規則是,無論何時您有多行/需要使用return關鍵字,您都必須明確定義返回類型或捕獲的值的類型。這種限制可能是由於在緊湊/退化情況下,您保證只有一個退出點 - val in val,因爲當您使用return關鍵字時,可能有多個返回點。在後一種情況下,您可能會在一行return 1上返回一個Int,並在另一行上返回nil。在這種情況下,讓編譯器抱怨明確假設是合理的。簡而言之,這需要編譯器中更復雜的類型推斷,並且他們可能還沒有做到這一點。

所以TL; DR,我同意這個建議將它報告爲一個錯誤,並在此期間從封閉中指定返回類型。正如你所說的,儘管如此,編譯器有足夠的上下文來推斷正確的類型。

注意,在除了你的例子,這種情況下也工作:

// inferring var dict as a context for lines below 
var dict = arrayToDictionary([1, 2, 3], { val in val }) 

// dict is already defined, so this works: 
dict = arrayToDictionary([1, 2, 3], { val in return val }) 

// explicit final type, compiler infers backwards 
let d2:Dictionary<Int, Int> = arrayToDictionary([1, 2, 3], { val in val }) 

// explicit return type, compiler infers "forewards" 
let d3 = arrayToDictionary([1, 2, 3], { val -> Int in return val })