我知道(Int) -> Void
不能被(Any) -> Void
类型化:
let intHandler: (Int) -> Void = { i in
print(i)
}
var anyHandler: (Any) -> Void = intHandler <<<< ERROR
这给出了:
错误:无法转换类型&#39;(Int) - &gt;的值虚空&#39;到指定的类型 &#39;(任何) - &gt;空隙&#39;
问题:但我不知道为什么会这样做?
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)
很抱歉,如果之前有人问这个问题。我还没有找到这样的问题,也许我不知道这里的关键字。 请赐教!
答案 0 :(得分:2)
所有关于variance和Swift的关闭。
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
。 <{1}}也会工作,而不是Any
,因为它更通用。
现在我们确定了这一点,让我们看看你的两个代码块中会发生什么。
第一个块尝试将一个更具体的参数闭包分配给一个不太具体的参数闭包,这不遵循方差规则,因此它不会编译。
第二块代码怎么样?我们处于类似于第一个块的场景:带有一个参数的闭包。
Error
或String
更具体Void
,因此我们可以将其用作返回值Any
比(Int) -> Void
(闭包差异规则)更具体,因此我们可以将其用作参数关系差异得到尊重,因此(Any) -> Void
和intResolver
是stringResolver
的兼容匹配。这听起来有点违反直觉,但仍然遵循编译规则,这允许分配。
anyResolver
即使MyGenericType<B>
,也无法分配到MyGenericType<A>
。例外情况是标准库结构,例如B: A
和Optional
。
答案 1 :(得分:1)
首先,让我们考虑为什么你的第一个例子是非法的:
let intHandler: (Int) -> Void = { i in
print(i)
}
var anyHandler: (Any) -> Void = intHandler
// error: Cannot convert value of type '(Int) -> Void' to specified type '(Any) -> Void'
(Any) -> Void
是一个可以处理任何输入的函数; (Int) -> Void
是一个只能 处理Int
输入的函数。因此,我们不能将Int
- 将函数视为可以处理任何的函数,因为它不能。如果我们使用anyHandler
调用String
?
另一种方式呢?这是合法的:
let anyHandler: (Any) -> Void = { i in
print(i)
}
var intHandler: (Int) -> Void = anyHandler
为什么呢?因为我们可以将处理任何的函数视为可以处理Int
的函数,因为如果它可以处理任何事情,根据定义它必须能够处理{{1 }}
所以我们已经确定我们可以将Int
视为(Any) -> Void
。让我们看看你的第二个例子:
(Int) -> Void
为什么我们可以将let intResolver: ((Int) -> Void) -> Void = { f in
f(5)
}
var anyResolver: ((Any) -> Void) -> Void = intResolver
视为((Int) -> Void) -> Void
?换句话说,为什么在调用((Any) -> Void) -> Void
时我们可以将anyResolver
参数转发到(Any) -> Void
参数?好吧,正如我们已经发现的那样,我们可以将(Int) -> Void
视为(Any) -> Void
,因此它是合法的。
同样的逻辑适用于(Int) -> Void
的示例:
((String) -> Void) -> Void
在致电let stringResolver: ((String) -> Void) -> Void = { f in
f("wth")
}
var anyResolver: ((Any) -> Void) -> Void = stringResolver
时,我们可以将anyResolver
传递给它,然后传递到(Any) -> Void
,其中stringResolver
。并且可以处理任何事物的函数也是处理字符串的函数,因此它是合法的。
使用返回类型工作:
(String) -> Void
由于let intResolver: ((Int) -> Void) -> String = { f in
f(5)
return "I want to return some string here."
}
var anyResolver: ((Any) -> Void) -> Any = intResolver
表示返回intResolver
,String
表示返回anyResolver
;一个字符串 Any
,所以它是合法的。