2015-06-10 28 views
21

A partire da Swift 2.0 sembra che possiamo avvicinarci alle estensioni di tipi generici applicabili a situazioni previste.Swift "where" Array Extensions

Anche se non possiamo ancora farlo:

protocol Idable { 
    var id : String { get } 
} 

extension Array where T : Idable { 
    ... 
} 

... ora possiamo fare questo:

extension Array { 
    func filterWithId<T where T : Idable>(id : String) -> [T] { 
    ... 
    } 
} 

... e Swift grammaticalmente lo accetta. Tuttavia, per la vita di me non riesco a capire come rendere felice il compilatore quando riempio i contenuti della funzione di esempio. Supponiamo che io dovessi essere il più esplicito possibile:

extension Array { 
    func filterWithId<T where T : Idable>(id : String) -> [T] { 
     return self.filter { (item : T) -> Bool in 
      return item.id == id 
     } 
    } 
} 

... il compilatore non accetterà la chiusura prevista per filtrare, lamentandosi

non può invocare 'filtro', con una lista di argomenti di tipo ' ((T) -> Bool) '

Simile se l'articolo è specificato come Idable. Qualcuno ha avuto fortuna qui?

risposta

37
extension Array { 
    func filterWithId<T where T : Idable>(id : String) -> [T] { 
    ... 
    } 
} 

definisce un metodo generico filterWithId() cui il generico segnaposto T è limitato per essere Idable. Ma questa definizione introduce un segnaposto locale T che non è completamente correlato al tipo di elemento dell'array T (e nasconde quello nell'ambito del metodo).

in modo da avere non ha precisato che gli elementi dell'array devono essere conformi alle Idable, e questo è il motivo per cui non è possibile chiamare self.filter() { ... } con una chiusura che si aspetta che gli elementi essere Idable.

Come di Swift 2/Xcode 7 beta 2, è possibile definire metodi di estensione su un tipo generico che sono più restrittive sul modello (confrontare Array extension to remove object by value per un problema molto simile):

extension Array where Element : Idable { 

    func filterWithId(id : String) -> [Element] { 
     return self.filter { (item) -> Bool in 
      return item.id == id 
     } 
    } 
} 

In alternativa, è possibile definire un metodo di estensione protocollo:

extension SequenceType where Generator.Element : Idable { 

    func filterWithId(id : String) -> [Generator.Element] { 
     return self.filter { (item) -> Bool in 
      return item.id == id 
     } 
    } 
} 

Poi filterWithId() è disponibile per tutti i tipi conformi a SequenceType (in particolare a Array) se il tipo di elemento di sequenza è conforme a Idable.

In Swift 3 questo sarebbe

extension Sequence where Iterator.Element : Idable { 

    func filterWithId(id : String) -> [Iterator.Element] { 
     return self.filter { (item) -> Bool in 
      return item.id == id 
     } 
    } 
} 
+0

Ah che abbia un senso un senso perfetto, grazie per l'apprendimento :) –

+0

@ yo.ian.g: Sei il benvenuto! –

+0

C'è un modo per farlo con i tipi non di protocollo, come 'estensione Array dove Iterator.Element: CGRect'? –