Swift 通用闭包总和

Swift generic closures sum

请问为什么一个代码可以正常工作而另一个却不行?

此代码工作正常:

typealias StyleClosure<T: UIView> = (T) -> ()

func +<T>(lhs: @escaping StyleClosure<T>,
          rhs: @escaping StyleClosure<T>) -> StyleClosure<T> {
    return { (value: T) -> Void in
        lhs(value)
        rhs(value)
    }
}

let s1: StyleClosure<UIView> = { (view: UIView) in
    view.layer.cornerRadius = 1
}

let s2: StyleClosure<UILabel> = { (view: UILabel) in
    view.font = UIFont.systemFont(ofSize: 14)
}

let s3 = s1 + s2

s3 是闭包,我可以将 UILabel 传递给它。而 func+ 可以接受两个闭包,包含不同的类型——UIView 和 UILabel。

但是下面的代码报错:

class Styler<T: UIView> {
    private let closure: (T) -> ()
    init(_ closure: @escaping (T) -> ()) {
        self.closure = closure
    }
    func apply(_ view: T) {
        self.closure(view)
    }
}
func +<T>(lhs: Styler<T>, rhs: Styler<T>) -> Styler<T> {
    return Styler { (value: T) in
        lhs.apply(value)
        rhs.apply(value)
    }
}

let styler1: Styler<UILabel> = Styler { (label: UILabel) -> Void in
    label.backgroundColor = UIColor.red
}

let styler2: Styler<UIView> = Styler { (view: UIView) -> Void in
    view.backgroundColor = UIColor.green
}

let styler3 = styler1 + styler2

此代码给出以下编译错误:

Cannot convert value of type 'Styler<UIView>' to expected argument type 'Styler<UILabel>'

有点明白,为什么第二个代码报错了。你知道为什么第一个代码没有错误吗?

您 运行 关注 的问题。 Swift 中的泛型类型是不变的,这意味着 Styler<A>Styler<B> 是完全不相关的类型,即使 AB 是相关的(例如子类)。

这就是 Style<UILabel>Styler<UIView> 不相关的原因。但是,闭包(以及函数)是变体(如 所解释的)- 在 return 类型上是协变的,在参数类型上是逆变的,这就是你的第一个示例有效的原因。

因此,您可以将 UILabel 传递给 Styler<UIView>.apply,因为这是一个简单的函数调用,它接受声明的输入参数类型的子类。

let styler1: Styler<UIView> = Styler { (label: UIView) -> Void in
    label.backgroundColor = UIColor.red
}

let styler2: Styler<UIView> = Styler { (view: UIView) -> Void in
    view.backgroundColor = UIColor.green
}

let styler3 = styler1 + styler2

styler1.apply(UILabel())