2015-06-10 16 views
21

Wygląda na to, że od Swift 2.0 możemy zbliżyć się do rozszerzeń typów ogólnych, które mają zastosowanie do predykowanych sytuacji.Swift "gdzie" Rozszerzenia Array

Chociaż nadal nie możemy tego zrobić:

protocol Idable { 
    var id : String { get } 
} 

extension Array where T : Idable { 
    ... 
} 

... teraz możemy to zrobić:

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

... i Swift gramatycznie akceptuje. Jednak dla mojego życia nie mogę wymyślić, jak sprawić, aby kompilator był zadowolony, gdy wypełniam zawartość przykładowej funkcji. Załóżmy, że miały być tak wyraźne, jak to możliwe:

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

... kompilator nie zaakceptuje zamknięcia przewidziany do filtrowania, skarżąc

nie może powoływać „filtr” z listy argumentów typu " ((T) -> Bool) '

Podobny element jest określony jako Idable. Czy ktoś tu miał szczęście?

Odpowiedz

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

określa ogólny sposób filterWithId() gdzie ogólny zastępczy T jest ograniczony za Idable. Ale definicja ta wprowadza lokalny obiekt zastępczy, który jest całkowicie niezwiązany z elementem tablicy typu: T (i ukrywa go w zakresie metody).

Więc trzeba nie określono, że elementy tablicy musi być zgodna do Idable, i to jest powód, dlaczego nie można nazwać self.filter() { ... } z zamknięciem, które oczekuje, że elementy być Idable.

Od Swift 2/Xcode 7 beta 2 można zdefiniować metody rozszerzenie na typ rodzajowy, które są bardziej restrykcyjne od szablonu (por Array extension to remove object by value za bardzo podobnego problemu):

extension Array where Element : Idable { 

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

Alternatywnie, można zdefiniować protokół metodę rozszerzenia:

extension SequenceType where Generator.Element : Idable { 

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

Następnie filterWithId() jest dostępna dla wszystkich typów zgodnych do SequenceType (w szczególności do Array), jeśli element sekwencjiodpowiada Idable.

W Swift 3 byłoby to

extension Sequence where Iterator.Element : Idable { 

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

Ah że sens sens, dziękuję za nauki :) –

+0

@ yo.ian.g: Zapraszamy! –

+0

Czy jest sposób na wykonanie tego z typów non-protocol, takich jak 'rozszerzenie Array gdzie Iterator.Element: CGRect'? –