将一个类型传递给一个通用的Swift扩展,或者理想地推断它 [英] Pass in a type to a generic Swift extension, or ideally infer it

查看:99
本文介绍了将一个类型传递给一个通用的Swift扩展,或者理想地推断它的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设您有

 类花式:UIView 

要查找所有同级 Fancy 视图。 没问题 ...

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

扩展,

 公共扩展UIView 
{
内部函数fancySiblings() - >([Fancy] )
{
return(self.superview!
.subviews
.filter {$ 0!= self}
.flatMap {$ 0 as?Fancy}

}
}

真棒,您现在可以

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



太棒了。

但是,

如何推广该扩展以使用任何UIView子类型?



理想情况下,扩展名可以推断类型,甚至?以及采取类型?



因此,类似...

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

}

然后你可以这样称呼它...

  for self.siblings(Prancy)
for self.siblings(UIButton)

你怎么能告诉一个通用扩展的类型来使用,就像那样?



看起来你可以向后推论,

 公共扩展UIView 
{
内部函数不可思议< T>() - >([T])
{
return(self.superview!
.subviews
.filter {$ 0!= self}
.flatMap {$ 0 as? T)

}


for f:花式in self.incredible()

for p:Prancy in self.incredible ()

这是惊人的,但不会以其他方式工作。



你甚至可以...

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

我仍然想知道如何在self.siblings(Fancy)中输入类似的类型,理想情况下甚至可以推断它。

解决方案

只需使用 .Type



pre $ 内部函数同胞< T>(something:T.Type) - >([T]){
...
}

之后 b
$ b

完整的工作示例:

  class Fancy:UIView {} 

public exte nsion UIView {
内部func兄弟< T>(_:T.Type) - >([T]){
return(self.superview!
.subviews
.filter {$ 0!= self}
.flatMap {$ 0 as? T}




让superView = UIView()
让view = UIView()
superView.addSubview )
superView.addSubview(UIView())
superView.addSubview(Fancy())

print(view.siblings(Fancy))

$ b

正确输出一个花式视图!






为了解决所需的添加,可以选择使用显式类型参数或生效编译器的类型推断。您可以在相同的扩展名中创建第二个方法

 内部函数siblings< T>() - >([T]) {
return siblings(T)
}

提供显式类型参数调用方法一,省略它会要求您使其可驱动,并将调用第二个函数,在内部调用第一个函数。






,您可以使用更多的 swifty 方式,并将显式类型参数设置为可选,默认 nil 。值得注意的是,在省略类型参数的情况下会强制推断:

  //电源扩展,它提供了馈入或表示键入
内部func兄弟姐妹< T>(_:T.Type?= nil) - > ([T]){
return(self.superview!
.subviews
.filter {$ 0!= self}
.flatMap {$ 0 as?T}

}

这将使您可以通过

调用该方法

  for self.siblings(Fancy)

甚至

  for f:Fancy in self.siblings()

两者都可以工作,但仍然只能定义一个函数。


Say you have

 class Fancy:UIView

you want to find all sibling Fancy views. No problem...

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

So, try an extension,

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

Awesome, you can now

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

Fantastic.

But,

How to generalize that extension to work with any UIView subtype?

Ideally, can the extension infer the type, even? As well as taking a type?

So, something like ...

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

and then you could call it something like this ...

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

How can you "tell" a generic extension the type to use, like that??

It seems you can "infer it backwards",

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()

Which is amazing but doesn't work the other way.

You can even...

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

So I would still like to know how to "pass in" a type something like for f in self.siblings(Fancy) and, ideally, even infer it also.

解决方案

Simply use the .Type:

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

Afterwards for f in self.siblings(Fancy) should work exactly as expected.

Full working example:

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))

Correctly outputs the one Fancy view!


To address the requested addition for optionally using the explicit type parameter or take effect of the type inference of the compiler. You can create a second method in the same extension

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

That way providing a explicit type parameter calls method one, omitting it will require you to make it inferable and will call the second function which in terms calls the first one internally.


Or, you can use the far more swifty way and make the explicit type argument an optional with default nil. That, remarkably, will force the inference in case of omitting the type argument:

// 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 }
        )
}

That will enable you to call the method either via

for f in self.siblings(Fancy)

or even

for f : Fancy in self.siblings()

Both will work while still only defining one function.

这篇关于将一个类型传递给一个通用的Swift扩展,或者理想地推断它的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆