2015-11-11 17 views
5

如果我理解正確,Swift可以通過不同的方式確定泛型的實際類型,包括按返回類型進行匹配。使用相同(或類似)機制來消除重載函數的歧義。所以這個按預期工作:Swift泛型選擇不會傳播

func getValue<T>()->T? { 
    return nil 
} 

func getValue()->Int? { 
    return 13 
} 

let b: Int? = getValue() 

當運行這個時,b將是13。從技術上講,兩個函數簽名都是合適的,但後者對於所請求的返回類型更具體。

讓我們添加第二個功能和隧道的呼叫通過它:

func getGetValue<T>()->T? { 
    return getValue() 
} 

let c: Int? = getGetValue() 

運行此,C將是nil。事實上,編譯器會選擇通用getValue()實現從getGetValue()中調用,這不是我想要的。恕我直言,請求的返回類型應該在getValue()的兩個實現之間進行選擇時通過第二個泛型傳播,從而產生與第一個示例中相同的行爲。

我錯過了什麼? (Xcode的7.1)

+0

很好的發現。我的猜測是,當存在另一層抽象時,推導式返回類型不起作用。一旦進入'getGetValue',編譯器不知道'T'類型是什麼,所以第一個函數是唯一匹配的函數。 –

+0

@ZoffDino這也是我的猜測,但我不明白爲什麼編譯器不能傳播自下而上的類型。從我的角度來看,它看起來像一個錯誤 - 但我不是編譯器的人。也許這種行爲有一個完全有效的理由。以防萬一,我會提交一份雷達。 –

+0

Swift博客中有一篇文章[內存安全:確保使用之前定義的值](https://developer.apple.com/swift/blog/?id=28),討論編譯器能夠證明多大程度的正確性的程序。我認爲這與你的問題有點相關 –

回答

0

我想明確地傳播泛型類型,它仍然無法正常工作(所以你說的沒錯,這是一個問題):

func getGetValue<T>()->T? { 
    guard let value: T? = getGetValue() 
    return value 
} 

這裏有一個稍微不同的方法,但是,這種可能會得到你正在尋找使用協議(使用協議允許我們保留一些類型信息)

// Protocol for getting a value 
protocol GetValue { 
    static func getValue() -> Self? 
} 

// Default implementation 
extension GetValue { 
    static func getValue() -> Self? { 
     return nil 
    } 
} 

// Int implementation 
extension Int: GetValue { 
    static func getValue() -> Int? { 
     return 13 
    } 
} 

// Our generic getGetValue function for any type that implements GetValue 
func getGetValue<T: GetValue>()->T? { 
    return T.getValue() 
} 

let a: Int? = getGetValue() // 13 

// Making String implement the protocol (It gets the default implementation) 
extension String: GetValue { 

} 

let b: String? = getGetValue() // nil