【发布时间】:2017-11-17 09:10:18
【问题描述】:
鉴于此示例代码:
private protocol P {}
final private class X {
private func j(j: (P) -> Void) -> Void {}
private func jj<Z: P>(jj: (Z) -> Void) -> Void {
j(j: jj)
}
}
XCode 9.1 中的 Swift 4 在 j(j: jj) 行给出了这个编译器错误:
无法将“(Z) -> Void”类型的值转换为预期的参数类型 ‘(P) -> 虚空’。
为什么?
注意,在我看来它不应该给出这个错误,因为类型约束<Z: P> 要求 Z 绝对必须符合协议 P。所以,绝对没有理由convert 从 Z 到 P,因为 Z 已经符合 P。
对我来说似乎是一个编译器错误......
【问题讨论】:
-
这段代码背后的想法是什么?
-
编译器是正确的——
(Z) -> Void不是(P) -> Void。为了说明为什么会这样,让我们说String : P和Int : P。现在让我们用Int替换Z。我们不能将(Int) -> Void传递给(P) -> Void。为什么?那么(P) -> Void接受符合P的任何东西——例如,我们可以传入String。但如果该函数实际上是(Int) -> Void,我们会尝试将String传递给Int,这显然是不合理的。 -
我不同意。因为我们在运行时对 Z 的唯一了解就是它是一个 P。它是否真的是一个 Int 或 String 完全无关紧要。
-
@CommaToast 否,在 runtime
Z是用具体类型实现的。它是P的子类型,但P不是它的子类型,就像在我上面的示例中String是P的子类型一样,但P不是@987654344 的子类型@.