2015-11-23 38 views
7

對不起,對於通用標題,很難描述沒有例子的問題。這個泛型函數發生了什麼?

假設我定義了被約束到Equatable類型以下通用功能:

func test<T: Equatable>(expect expected: T, run:() -> T) { 
    let value = run() 
    if value == expected { 
     print("OK") 
    } else { 
     print("Expected: \(expected), Actual: \(value)") 
    } 
} 

這裏的使用表示函數的例子:

test(expect: 100) { 10 * 10 } // prints "OK" 
test(expect: 1000) { 10 * 10 } // prints "Expected: 1000, Actual: 100" 

,當然,我可以存儲值,而不是使用文本:

let e = 100 
test(expect: e) { e } // prints "OK" 

到目前爲止,一切都按預期工作(沒有雙關語)。

現在讓我們來試試這個有一個數組:

test(expect: [1, 2]) { [1, 2] } // prints "OK" 

再次,工作的事情了。

但我們現在試試這個:

let a = [1, 2] 
test(expect: a) { a } // error: cannot convert value of type '() -> [Int]' to expected argument type '() -> _' 

所以我一直在建立的問題是:爲什麼不這項工作?

遊樂場正確推斷的a類型爲[Int],所以來自哪裏的() -> _的期望?

嘗試了一堆最後一個示例的變化:

test(expect: a) { return a } 
test(expect: a) { return a as [Int] } 
test(expect: a as [Int]) { return a as [Int] } 
test(expect: [1, 2]) { a } 
test(expect: [1, 2] as [Int]) { a } 

它們都導致了同樣的問題。由於某些原因,Swift似乎認爲該函數預計爲() -> _

因此,也許這只是因爲數組不是Equatable,但這個工程:

let a = [1, 2] 
[1, 2] == [1, 2] 
a == a 

我想我明白仿製藥非常好,而且我完全被這個難住了。這是Swift中的錯誤還是我的定義中的錯誤test()?目標是否能夠完成?

解決方案

感謝@下面Sulthan的回答,我能寫(以及與此有關的任何SequenceType)這個函數來處理數組情況下另一個版本:

public func test<T: SequenceType where T.Generator.Element: Equatable>(expect expected: T, run:() -> T) { 
    let result = run() 
    // Note: zip() will stop at the shorter array, so this implementation isn't correct, don't use it (it will incorrectly end up saying [1] == [1,2]). This code is just here to demonstrate the function's generic constraint. 
    let eq = zip(expected, result).filter(!=).isEmpty 
    if eq { 
     print("OK") 
    } else { 
     print("Expected: \(expected), Actual: \(result)") 
    } 
} 

let a: [Int] = [1, 2] 
test(expect: [1,2]) { a } // prints "OK" 
test(expect: [1,3]) { a } // prints "Expected: [1, 3], Actual: [1, 2]" 
+2

答案與http://stackoverflow.com/a/33732669/669586相同,但我不確定是否應該將其作爲副本關閉。 – Sulthan

+1

@Sulthan從它的根本來看,這絕對是一個相同的問題,但通過函數來​​完成這個事實混淆了這個問題,我覺得它值得站在自己的位置上。此外,問題的一部分是如何做這項工作,這個問題的編輯也解決。 – vopilif

+0

作爲關於我上面的「解決方案」的一個附註。將'test()'的實現約束到'SequenceType'可能是一個壞主意,因爲它有無限序列的有效性,所以你不想試圖迭代所有的序列。 'CollectionType'會更合適。 – vopilif

回答

5

陣列唐不會自動符合Equatable,即使它們的值是Equatable。但是,如果直接使用數組文本,編譯器會嘗試匹配該類型並將數組轉換爲符合EquatableNSArray

+0

這就是它!哇,這一直困擾着我一段時間!謝謝! – vopilif

+1

其實,玩這個更多..你確定這是將其轉換爲NSArray?如果我刪除'import Foundation',我不能再使用NSArray,但是[1,2,3] == [1,2,3]'仍然可以工作,所以其他的事情必須繼續。 – vopilif

+1

@vopilif有'=='定義的'元素:Equatable'的數組。這並不意味着Array實現了'Equatable'。 – Sulthan