2015-11-03 78 views
39

我試圖與協議混合泛型和我得到一個很艱難的時期的xD使用作爲具體類型符合其他協議不受支持

我已經在Android/Java的某些架構實現了一些協議項目,我試圖重寫它,以適應它在一個快速/ iOS項目。但是我發現這個限制。

ProtocolA

protocol ProtocolA { 

} 

ProtocolB

protocol ProtocolB : ProtocolA { 

} 

ImplementProtocolA

class ImplementProtocolA <P : ProtocolA> { 

    let currentProtocol : P 

    init(currentProtocol : P) { 
     self.currentProtocol = currentProtocol 
    } 

} 

ImplementProtocolB

class ImplementProtocolB : ImplementProtocolA<ProtocolB> { 

} 

所以,當我嘗試設置ProtocolB作爲實現ProtocolA的具體類型,我得到這個錯誤:

使用 'ProtocolB' 作爲具體類型符合的協議'ProtocolA'不支持

1是否有任何理由對此「限制」?

2是否有任何解決方法來實現它?

3它在某些時候會被支持嗎?

--UPDATED--

同樣的問題的另一個變種,我想:

查看協議

protocol View { 

} 

protocol GetUserView : View { 
    func showProgress() 
    func hideProgress() 
    func showError(message:String) 
    func showUser(userDemo:UserDemo) 
} 

演示協議

protocol Presenter { 
    typealias V : View 
} 

class UserDemoPresenter : Presenter { 
    typealias V = GetUserView 
} 

錯誤:

UserDemoPresenter.swift Possibly intended match 'V' (aka 'GetUserView') does not conform to 'View’

那是什麼?它符合!

即使我使用View而不是GetUserView,它也不會編譯。

class UserDemoPresenter : Presenter { 
    typealias V = View 
} 

UserDemoPresenter.swift Possibly intended match 'V' (aka 'View') does not conform to 'View'

xxDD我不明白這一點,真的。

--UPDATED--

由羅布·納皮爾提出瞭解決問題是不固定的,相反,它只是推遲。

當試圖定義到UserDemoPresenter一個參考,我需要指定泛型類型,所以我得到了同樣的錯誤:

private var presenter : UserDemoPresenter<GetUserView> 

Using 'GetUserView' as a concrete type conforming to protocol 'GetUserView' is not supported

+2

此處還觀察到:http:// stackoverflow。COM /問題/ 33112559 /協議犯規,符合到自身。 –

回答

41

的根本原因的限制是,斯威夫特沒有按」沒有一流的元類型。最簡單的例子是,這不起作用:

func isEmpty(xs: Array) -> Bool { 
    return xs.count == 0 
} 

從理論上講,這個代碼可以工作,如果它確實會有很多其他類型的我可以做(如函子和單子,這確實能今天不會在Swift中表達)。但你不能。你需要幫助Swift把它歸結爲具體的類型。我們經常做的泛型:

func isEmpty<T>(xs: [T]) -> Bool { 
    return xs.count == 0 
} 

注意T在這裏完全是多餘的。我沒有理由表達它;它從未使用過。但是斯威夫特需要它,所以它可以將摘要Array轉化爲具體的[T]。你的情況也是如此。

這是一個具體類型(當然,它是會變成一個具體類型它的實例化和P填充任何時候抽象類型):

class ImplementProtocolA<P : ProtocolA> 

這是一個完全抽象類型斯威夫特沒有任何規則可以變成具體類型:

class ImplementProtocolB : ImplementProtocolA<ProtocolB> 

你需要使它具體化。這將編譯:

class ImplementProtocolB<T: ProtocolB> : ImplementProtocolA<T> {} 

而且也:

class UserDemoPresenter<T: GetUserView> : Presenter { 
    typealias V = T 
} 

只是因爲你很可能會在以後運行到這個問題:你的生活會容易得多,如果你讓這些結構或final類。混合協議,泛型和類多態性充滿了非常尖銳的邊緣。有時你很幸運,它不會編譯。有時它會調用你不期望的東西。

您可能感興趣的A Little Respect for AnySequence其中詳細一些相關問題。


private var presenter : UserDemoPresenter<GetUserView> 

這仍然是一個抽象的類型。您的意思是:

final class Something<T: GetUserView> { 
    private var presenter: UserDemoPresenter<T> 
} 

如果這樣會產生問題,您需要創建一個框。請參閱Protocol doesn't conform to itself?以瞭解如何鍵入擦除以便您可以保存抽象類型。但你需要在具體類型中工作。你最終無法專注於協議。在大多數情況下,你最終必須專注於具體的事情。

+0

非常感謝您的解答和解釋。您能否提供一個使用結構而不是類的代碼示例,以便充分理解您所建議的內容? –

+1

我只是指在代碼中用'struct'替換單詞'class'。如果你使用'struct',你會得到價值語義(當你將它傳遞給一個函數時,函數會獲得它自己的獨立副本)。如果你需要引用語義(當你把它傳遞給一個函數時,調用者可以看到函數對它的修改),然後使用'final class'。 'struct'和'final class'都禁止子類化,這使事情變得更容易。 (子類帶來了很多瘋狂。) –

+0

好的,謝謝!我打算做最後的決賽,事實上它在最初的java項目中是最終的。但我想我會繼續使用類而不是結構,我需要這個項目儘可能模仿java項目中定義的行爲,並且更改struct的類可能會導致真正非常不同的場景xD –

相關問題