used type parameter only not inferred has generic functions extension could constraint because associated ios swift generics functional-programming swift-extensions

ios - type - Pase un tipo a una extensión Swift genérica, o infórmelo idealmente



public extension swift (2)

Di que tienes

class Fancy:UIView

Usted quiere encontrar todas las vistas de Fancy hermanos. No hay problema

for v:UIView in superview!.subviews { if let f = v as? Fancy { f.hungry = false } }

Entonces, intente una extensión,

public extension UIView { internal func fancySiblings()->([Fancy]) { return (self.superview! .subviews .filter { $0 != self } .flatMap { $0 as? Fancy } ) } }

Impresionante, ahora puedes

for f:Fancy in self.fancySiblings() { f.hungry = false }

Fantástico.

Pero,

¿Cómo generalizar esa extensión para trabajar con cualquier subtipo UIView?

Idealmente, ¿puede la extensión inferir el tipo , incluso? ¿Así como tomar un tipo?

Entonces, algo como ...

public extension UIView { internal func siblings<T>( something T )->([T]) { return (self.superview! .subviews .filter { $0 != self } .flatMap { $0 as? T } ) }

y entonces podrías llamarlo algo como esto ...

for f in self.siblings(Fancy) for p in self.siblings(Prancy) for b in self.siblings(UIButton)

¿Cómo puedes "decirle" a una extensión genérica el tipo de uso, así?

Parece que puedes "inferirlo al revés",

public extension UIView { internal func incredible<T>()->([T]) { return (self.superview! .subviews .filter { $0 != self } .flatMap { $0 as? T } ) } for f:Fancy in self.incredible() for p:Prancy in self.incredible()

Lo cual es asombroso pero no funciona de otra manera.

Usted puede incluso...

self.siblings().forEach{ (f:Fancy) in d.hasRingOn = false }

Así que todavía me gustaría saber cómo "pasar" un tipo como for f in self.siblings(Fancy) e, idealmente, incluso inferirlo.


Respuesta similar a lo que se ha dicho anteriormente, pero un poco más simplificado y sin tener que pasar nada o iterar las subvistas más de una vez:

extension UIView { internal func siblings<T: UIView>() -> [T] { return superview?.subviews.flatMap {return ($0 == self) ? nil : ($0 as? T) } ?? [] } }

o mi preferencia usando opcionales:

internal func siblings<T: UIView>() -> [T]? { return superview?.subviews.flatMap {return ($0 == self) ? nil : $0 as? T } }

Ejemplo de uso:

class ExampleView: UIView { func getMatchingSiblings(){ let foundSiblings: [ExampleView] = siblings() } //or with the for loop in the question: for item: ExampleView in siblings() { } }

Cuando se trata de genéricos, simplemente necesita una instancia del tipo genérico en la firma del método. Por lo tanto, si tiene un parámetro o un tipo de retorno que usa el genérico, no necesita pasar el tipo.


Simplemente use el .Type :

internal func siblings<T>( something : T.Type)->([T]) { ... }

Luego for f in self.siblings(Fancy) debería funcionar exactamente como se esperaba.

Ejemplo completo de trabajo:

class Fancy : UIView {} public extension UIView { internal func siblings<T>( _ : T.Type)->([T]) { return (self.superview! .subviews .filter { $0 != self } .flatMap { $0 as? T } ) } } let superView = UIView() let view = UIView() superView.addSubview(view) superView.addSubview(UIView()) superView.addSubview(Fancy()) print(view.siblings(Fancy))

Salidas correctamente la una vista de Fancy !

Para abordar la adición solicitada para usar opcionalmente el parámetro de tipo explícito o hacer efecto la inferencia de tipo del compilador. Puedes crear un segundo método en la misma extensión.

internal func siblings<T>()->([T]) { return siblings(T) }

De esa manera, al proporcionar un tipo explícito, el parámetro llama al método uno, omitiéndolo requerirá que lo hagas inferable y llamará a la segunda función, que en términos de llamada llama a la primera internamente.

O bien , puede usar la forma mucho más rápida y hacer que el argumento de tipo explícito sea opcional con el valor predeterminado nil . Eso, notablemente, forzará la inferencia en caso de omitir el argumento de tipo:

// power extension, it provides both infered or stated typing internal func siblings<T>(_ : T.Type? = nil) -> ([T]) { return (self.superview! .subviews .filter { $0 != self } .flatMap { $0 as? T } ) }

Eso te permitirá llamar al método a través de

for f in self.siblings(Fancy)

o incluso

for f : Fancy in self.siblings()

Ambos funcionarán mientras que solo definen una función.