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>
是完全不相关的类型,即使 A
和 B
是相关的(例如子类)。
这就是 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())
请问为什么一个代码可以正常工作而另一个却不行?
此代码工作正常:
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>'
有点明白,为什么第二个代码报错了。你知道为什么第一个代码没有错误吗?
您 运行 关注 Styler<A>
和 Styler<B>
是完全不相关的类型,即使 A
和 B
是相关的(例如子类)。
这就是 Style<UILabel>
和 Styler<UIView>
不相关的原因。但是,闭包(以及函数)是变体(如
因此,您可以将 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())