将类型传递给通用Swift扩展,或者理想地推断它

Fat*_*tie 20 generics functional-programming ios swift swift-extensions

说你有

 class Fancy:UIView
Run Code Online (Sandbox Code Playgroud)

你想找到所有兄弟姐妹的Fancy意见. 没问题 ......

    for v:UIView in superview!.subviews
        {
        if let f = v as? Fancy
            { f.hungry = false }
        }
Run Code Online (Sandbox Code Playgroud)

所以,尝试扩展,

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

太棒了,你现在可以

    for f:Fancy in self.fancySiblings()
        { f.hungry = false }
Run Code Online (Sandbox Code Playgroud)

太棒了.

但,

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

理想情况下,扩展可以推断出类型吗?还有一个类型?

所以,像......

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

然后你可以称之为......

    for f in self.siblings(Fancy)
    for p in self.siblings(Prancy)
    for b in self.siblings(UIButton)
Run Code Online (Sandbox Code Playgroud)

你怎么能"告诉"一个通用扩展使用的类型,比如??

看来你可以"向后推断",

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()
Run Code Online (Sandbox Code Playgroud)

这是惊人的,但不是相反的方式.

你甚至可以......

    self.siblings().forEach{
        (f:Fancy) in
        d.hasRingOn = false
        }
Run Code Online (Sandbox Code Playgroud)

所以我仍然想知道如何"传入"类似的东西for f in self.siblings(Fancy),理想情况下,甚至推断它.

luk*_*302 19

只需使用.Type:

internal func siblings<T>( something : T.Type)->([T]) {
    ...
}
Run Code Online (Sandbox Code Playgroud)

之后for f in self.siblings(Fancy)应该完全按预期工作.

完整的工作示例:

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))
Run Code Online (Sandbox Code Playgroud)

正确输出一个Fancy视图!


要解决所请求的添加,以便可选地使用显式类型参数或生成编译器的类型推断.您可以在同一扩展中创建第二个方法

internal func siblings<T>()->([T]) {
    return siblings(T)
}
Run Code Online (Sandbox Code Playgroud)

这样提供一个显式类型参数调用方法一,省略它将要求你使它成为可推断的并将调用第二个函数,在内部调用第一个函数.


或者,您可以使用更加流畅的方式,并使显式类型参数成为可选的默认值nil.显然,这将在省略类型参数的情况下强制推断:

// 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 }
        )
}
Run Code Online (Sandbox Code Playgroud)

这将使您能够通过调用方法

for f in self.siblings(Fancy)
Run Code Online (Sandbox Code Playgroud)

甚至

for f : Fancy in self.siblings()
Run Code Online (Sandbox Code Playgroud)

两者都可以工作,但仍然只定义一个功能.

  • "Swift.它可以让你花费相当长的时间来完善令人难以置信的短代码." :) (5认同)
  • @JoeBlow你可以使type参数成为可选的,默认值为`nil`(`_:T.Type?= nil`).这可以让你在有或没有类型的情况下调用方法.标准推断应该正常工作. (2认同)