2015-07-18 12 views
19

Posso aggiungere la conformità del protocollo a un protocollo tramite un'estensione rapida?Swift 2 aggiunge la conformità del protocollo ai protocolli

//Plain old protocol here 
protocol MyData { 
    var myDataID: Int { get } 
} 

Voglio fare il protocollo MyData equatable di default (basta confrontare l'ID)

extension MyData : Equatable { } 

ma ottengo questo incantevole errore:

"Extension of protocol 'MyData' cannot have an inheritance clause"

Il comportamento che sto cercando è BananaData conforme a Equatable (un protocollo) perché implementa il protocollo MyData che può fornire un'implementazione predefinita di Equitable

//This is the method to implement Equatable 
func ==(lhs: MyData, rhs: MyData) -> Bool { 
    return lhs.myDataID == rhs.myDataID 
} 

struct BananaData: MyData { 
    var myDataID: Int = 1 
} 

func checkEquatable(bananaOne: BananaData, bananaTwo: BananaData) { 
    //This compiles, verifying that BananaData can be compared 
    if bananaOne == bananaTwo { } 
    //But BananaData is not convertible to Equatable, which is what I want 
    let equatableBanana = bananaOne as Equatable 
    //I don't get the additional operations added to Equatable (!=) 
    if bananaOne != bananaTwo { } //Error 
} 

risposta

23

Come dice il messaggio di errore: un'estensione di un protocollo non può avere una clausola di ereditarietà. Invece, è possibile rendere il protocollo MyData ereditato da Equatable nella dichiarazione originale.

protocol MyData: Equatable { 
    var myDataID: Int { get } 
} 

Si potrebbe quindi estendere aggiungere un'implementazione di == per i tipi che sono conformi alle MyData:

func == <T: MyData>(lhs: T, rhs: T) -> Bool { 
    return lhs.myDataID == rhs.myDataID 
} 

Tuttavia, altamente raccomanda questo! Se si aggiungono altre proprietà a tipi conformi, le loro proprietà non verranno verificate per l'uguaglianza. Prendiamo l'esempio di seguito:

struct SomeData: MyData { 
    var myDataID: Int 
    var myOtherData: String 
} 

let b1 = SomeData(myDataID: 1, myOtherData: "String1") 
let b2 = SomeData(myDataID: 1, myOtherData: "String2") 

b1 == b2 // true, although `myOtherData` properties aren't equal. 

Nel caso di cui sopra avresti bisogno di ignorare == per SomeData per il risultato corretto, rendendo così il == che accetta MyData ridondante.

+0

Piccolo follow-up, ho dato per scontato che chi implementato 'MyData' deve anche implementare in modo esplicito equatable. Per esempio. Implementare Equitable è un requisito per MyData (che è quello che volevo evitare). Il 'BananaData' è ovviamente un esempio fornito, ma grazie per l'avvertimento. – Kevin

2

Questo parco giochi fa ciò che vuoi? L'ho fatta in base a quello che ho capito da Protocol-Oriented Programming in Swift dal WWDC 2015.

import Foundation 

//Plain old protocol here 

func == (lhs: MyData, rhs: MyData) -> Bool { 
    return lhs.myDataID == rhs.myDataID 
} 

func != (lhs: MyData, rhs: MyData) -> Bool { 
    return lhs.myDataID != rhs.myDataID 
} 

protocol MyData { 
    var myDataID: Int { get } 
} 

extension MyData where Self: Equatable { 

} 


struct BananaData: MyData { 
    var myDataID: Int = 1 
} 

func checkEquatable(bananaOne: BananaData, bananaTwo: BananaData) { 
    //This compiles, verifying that BananaData can be compared 
    if bananaOne == bananaTwo { 
     print("Same") 
    } 
    //But BananaData is not convertible to Equatable, which is what I want 
    //I don't get the additional operations added to Equatable (!=) 
    print(bananaOne.myDataID) 
    print(bananaTwo.myDataID) 


    if bananaOne != bananaTwo { 

    } 

    //Error 


} 

let b1 = BananaData(myDataID: 2) 
let b2 = BananaData(myDataID: 2) 

checkEquatable(b1, bananaTwo: b2) 

let c = b1 == b2 // Evaluates as true 
+0

Se una proprietà struct è conforme a Equitable (usando '=='), si ottiene automaticamente la funzione '! ='. Stavo usando '! =' Per verificare se 'BananaData' fosse effettivamente conforme al protocollo' Equatable' invece di avere un metodo '=='. Così, mentre compilavo il mio test case, quello che stavo davvero cercando era un modo per implementare 'Equatable' per tutte le strutture' MyData'. – Kevin

+2

Ciao @Kevin. Non so se questo faccia la differenza, ma vedo che si verifica un errore quando si esegue questa operazione ... 'estensione MyData: Equitable {}' ma non si ottiene un errore quando si esegue un'estensione di protocollo limitata come questa 'estensione MyData dove Self: Equitable {}' – Vader

Problemi correlati