let intHandler: (Int) -> Void = { i in print(i) } var anyHandler: (Any) -> Void = intHandler <<<< ERROR
这给出了:
error: cannot convert value of type ‘(Int) -> Void’ to specified type
‘(Any) -> Void’
问:但我不知道为什么这个工作?
let intResolver: ((Int) -> Void) -> Void = { f in f(5) } let stringResolver: ((String) -> Void) -> Void = { f in f("wth") } var anyResolver: ((Any) -> Void) -> Void = intResolver
我弄乱了返回类型,它仍然可以工作……:
let intResolver: ((Int) -> Void) -> String = { f in f(5) return "I want to return some string here." } let stringResolver: ((String) -> Void) -> Void = { f in f("wth") } var anyResolver: ((Any) -> Void) -> Any = intResolver (or stringResolver)
对不起,如果以前询问过.我还没有找到这样的问题,也许我不知道这里的关键字.
请赐教!
Swift在闭包返回类型方面是协变的,在其参数方面是反变量.这使得具有相同返回类型或更具体的闭包,以及相同的参数或更不具体的闭包是兼容的.
因此(Arg1) – >可以将Res1分配给(Arg2) – > Res2如果Res1:Res2和Arg2:Arg1.
为了表达这一点,让我们稍微调整一下第一个闭包:
import Foundation let nsErrorHandler: (customstringconvertible) -> NSError = { _ in return NSError(domain: "",code: 0,userInfo: nil) } var anyHandler: (Int) -> Error = nsErrorHandler
上面的代码有效,因为Int符合customstringconvertible,而NSError符合Error.任何人都会工作而不是错误,因为它更通用.
现在我们建立了这个,让我们看看你的两个代码块中会发生什么.
第一个块尝试将一个更具体的参数闭包分配给一个不太具体的参数闭包,这不遵循方差规则,因此它不会编译.
第二块代码怎么样?我们处于与第一个块类似的场景:具有一个参数的闭包.
>我们知道String或Void比Any更具体,所以我们可以将它用作返回值
>(Int) – > Void比(Any)更具体 – > Void(闭包方差规则),因此我们可以将它用作参数
闭合方差得到遵守,因此intResolver和stringResolver是anyResolver的兼容匹配.这听起来有点违反直觉,但仍然遵循编译规则,这允许分配.
事情变得复杂但是如果我们想要使用闭包作为通用参数,则方差规则不再适用,并且这是由于Swift泛型(具有少数例外)在其类型方面是不变的:MyGenericType< B>无法分配给MyGenericType< A>即使B:A.例外是标准库结构,如Optional和Array.