简体   繁体   English

Swift 通用闭包总和

[英]Swift generic closures sum

Could you please tell, why one code does work ok and another doesn't?你能告诉我为什么一个代码可以正常工作而另一个不能吗?

This code works ok:此代码工作正常:

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 is closure, I can pass UILabel to it. s3 是闭包,我可以将 UILabel 传递给它。 And func + can accept two closures, containing different types - UIView and UILabel.并且 func+ 可以接受两个闭包,包含不同的类型 - UIView 和 UILabel。

But the following code gives an error:但是下面的代码给出了一个错误:

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

This code gives following compile error:此代码给出以下编译错误:

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

I kind of understand, why the second code gives an error.我有点理解,为什么第二个代码会出错。 Do you have any idea, why first code gives no errors?你有什么想法,为什么第一个代码没有错误?

You are running into the issue of Swift generic coercion misunderstanding .您遇到了Swift generic coercion misunderstanding的问题。 Generic types in Swift are invariant, which means that Styler<A> and Styler<B> are completely unrelated types even if A and B are related (subclasses for instance). Swift 中的泛型类型是不变的,这意味着Styler<A>Styler<B>是完全不相关的类型,即使AB相关(例如子类)。

This is why Style<UILabel> and Styler<UIView> are unrelated.这就是Style<UILabel>Styler<UIView>不相关的原因。 However, closures (and hence functions) are variant (as explained here ) - covariant on the return type, and contravariant on the parameter types, this is why your first example works.但是,闭包(以及因此的函数)是变体的(如此所述)-返回类型是协变的,参数类型是逆变的,这就是您的第一个示例有效的原因。

Because of this, you can pass a UILabel to a Styler<UIView>.apply , since that is a simple function call, which accepts subclasses of the declared input argument type.因此,您可以将UILabel传递给Styler<UIView>.apply ,因为这是一个简单的 function 调用,它接受声明的输入参数类型的子类。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM