2017-02-23 15 views
1

任何人都可以向我解釋爲什麼這個例子中的最後一種情況是編譯錯誤?通用函數和子類。任何人都可以解釋此編譯錯誤?

class A{} 
class B: A{} 

protocol Finder{ 
    func find< T: A>(_ f: (T)->Bool) -> T? 
} 

class FinderImpl : Finder{ 
    func find<T : A>(_ f: (T) -> Bool) -> T? { 
     //In the real code I use T to find the instance. I.e. CoreData 
     return nil 
    } 
} 

let finder = FinderImpl() 

//OK 
let optionalB : B? = finder.find{_ in true} 
let a : A = finder.find{_ in true}! 
let b : B = finder.find{(b: B) in true}! 

//Compile Error 
let b2 : B = finder.find{_ in true}! 

let a。編譯器使用(A) -> Bool.作爲閉包類型。然後返回類型爲A.

讓b。這是因爲關閉具有明確的信息編譯:(B)->Bool

let optionalB。我不知道爲什麼這個案件有效,在這裏封閉也沒有任何信息。區別在於! operator

錯誤:在最後一種情況下,編譯器無法推斷傳遞給func find的閉包的類型。它建議我投as! B,因爲它認爲封閉類型是(A)->Bool。它不使用

重要參考B2型B的:我不能投as! B,因爲我需要查找功能實際使用的B型。如果我投as! B,該函數將使用A型和獲得錯誤的例子。代碼會編譯,但結果是錯誤的。

如果我刪除了T:A限制,則不存在編譯錯誤。

這看起來像是一個編譯器bug。我認爲編譯器應該使用b2的類型來知道閉包是(B)->Bool,然後是find的結果類型。 T:A限制和閉包中缺少類型信息會導致失敗。

我失去了一些東西在這裏?有什麼想法嗎?

回答

0

因爲在上例中,Swift無法推斷返回類型。

在您的通用功能,你宣稱T必須AA子類:

func find<T : A>(_ f: (T) -> Bool) -> T? { 
    return nil 
} 

斯威夫特可以推斷出什麼T實際上是在指定的閉合類型。這就是爲什麼這工作:

finder.find{(b: B) in true}! 
       ^now T == B 

在這裏,你沒有提供任何類型的信息,所以編譯器依靠的僅僅是通用函數的聲明,它說T : A

finder.find{ _ in true}! // this return A 
      ^what type is this? The compiler doesn't have any extra 
       information so it must be A according to the declaration 

你可以通過做一個明確的轉換得到它的編譯器:

let b2 : B = finder.find{ _ in true}! as! B 

或提供類型的信息:

let b3 : B = finder.find{ (_: B) in true}! 

(這是爲了讓它只編譯。代碼顯然會在運行時崩潰,因爲你正在強制展開一個零值)

+0

嗨,謝謝你的回答。我理解你的觀點,我想我也是在這個問題中提到的。我看到的問題是,在讓b2:B,我實際上指定了類型信息。 T = B。我不明白爲什麼有必要明確說明(B) - > Bool。以可選B爲例,那裏我沒有指定閉包類型,但它的工作原理。這就是爲什麼我認爲這可能是一個編譯器錯誤。有什麼想法嗎? – Lio

相關問題