2015-09-24 26 views
3

對於Swift的Dictionary結構上的泛型方法,我有兩個幾乎完全相同的斷言,但一個成功,另一個失敗。我認爲這是XCTAssert的工作原理,但不明白爲什麼。有沒有人有一個想法,爲什麼?在Swift中使用泛型方法的XCTAssert

如果該方法不是通用的,並且例如TString,則兩個測試都會成功。

extension Dictionary { 
    func safeElement<T>(key: Key, fallback: T) -> T { 
     if let value = self[key] as? T { 
      return value 
     } 
     return fallback 
    } 
} 

class DictionaryTests: XCTestCase { 
    let dict = ["foo": "bar"] 

    func testSafeElement() { 
     // This succeeds 
     let bar = dict.safeElement("foo", fallback: "") 
     XCTAssertEqual(bar, "bar") 

     // This fails 
     XCTAssertEqual(dict.safeElement("foo", fallback: ""), "bar") 
    } 
} 

更新

我與它擺弄多一點點,而且事實證明,如果你傳遞一個類型作爲參數,則這兩種情況下取​​得成功。但我想象這種類型的冗長並不是人們想要的。

extension Dictionary { 
    func safeElement<T>(key: Key, fallback: T, type: T.Type) -> T { 
     if let value = self[key] as? T { 
      return value 
     } 
     return fallback 
    } 
} 

class DictionaryTests: XCTestCase { 
    let dict = ["foo": "bar"] 

    func testSafeElement() { 
     // This succeeds 
     let bar = dict.safeElement("foo", fallback: "", type: String.self) 
     XCTAssertEqual(bar, "bar") 

     // This also succeeds 
     XCTAssertEqual(dict.safeElement("foo", fallback: "", type: String.self), "bar") 
    } 
} 

回答

2

如果添加一個print語句:

func safeElement<T>(key: Key, fallback: T) -> T { 
    print("calling for \(T.self)") 

你可以看到不同的輸出兩次試驗:

calling for String 
calling for Optional<String> 

這可能是因爲XCTAssertEqual的說法被聲明爲@autoclosure expression1:() -> T? ,因此編譯器會嘗試選擇返回可選項的safeElement版本,通過製作T==String?可以輕鬆完成。但那麼你的as? T做錯了,因爲字典的值類型是非可選String

聽起來像a bug

+0

將盡力報告,謝謝。 –

+1

我增加了一些關於爲什麼我認爲它發生的更多細節。 – jtbandes

+0

我已經更新了這個問題,也許它會給你更多的想法。 –