类型转换/多态如何在 Swift 中使用这种嵌套的闭包类型?

How does typecasting/polymorphism work with this nested, closure type in Swift?(类型转换/多态如何在 Swift 中使用这种嵌套的闭包类型?)
本文介绍了类型转换/多态如何在 Swift 中使用这种嵌套的闭包类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道 (Int) ->Void 不能被类型转换为 (Any) ->无效:

I know that (Int) -> Void can't be typecasted to (Any) -> Void:

let intHandler: (Int) -> Void = { i in
    print(i)
}
var anyHandler: (Any) -> Void = intHandler <<<< ERROR

这给出了:

错误:无法将类型 '(Int) -> Void' 的值转换为指定类型'(任何)-> 无效'

error: cannot convert value of type '(Int) -> Void' to specified type '(Any) -> Void'

<小时>

问题:但我不知道为什么会这样?


Question: But I don't know why this work?

let intResolver: ((Int) -> Void) -> Void = { f in
    f(5)
}

let stringResolver: ((String) -> Void) -> Void = { f in
    f("wth")
}

var anyResolver: ((Any) -> Void) -> Void = intResolver

我弄乱了返回类型,但它仍然有效...:

I messed around with the return type and it still works...:

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)

抱歉,如果之前有人问过这个问题.我还没有找到这种问题,也许我不知道这里的关键字.请赐教!

Sorry if this is asked before. I couldn't find this kind of question yet, maybe I don't know the keyword here. Please enlighten me!

如果您想尝试:https://iswift.org/playground?wZgwi3&v=3

推荐答案

这都是关于 variance 和 Swift 闭包.

It's all about variance and Swift closures.

Swift 在闭包返回类型方面是协变的,在其参数方面是逆变的.这使得具有相同返回类型或更具体的返回类型以及相同或不太具体的参数的闭包是兼容的.

Swift is covariant in respect to closure return type, and contra-variant in respect to its arguments. This makes closures having the same return type or a more specific one, and same arguments or less specific, to be compatible.

因此 (Arg1) ->Res1 可以分配给 (Arg2) ->Res2 if Res1: Res2 and Arg2: Arg1.

Thus (Arg1) -> Res1 can be assigned to (Arg2) -> Res2 if Res1: Res2 and Arg2: Arg1.

为了表达这一点,让我们稍微调整一下第一个闭包:

To express this, let's tweak a little bit the first closure:

import Foundation

let nsErrorHandler: (CustomStringConvertible) -> NSError = { _ in
    return NSError(domain: "", code: 0, userInfo: nil)
}
var anyHandler: (Int) -> Error = nsErrorHandler

上面的代码之所以有效,是因为Int 符合CustomStringConvertible,而NSError 符合Error.Any 也可以代替 Error 工作,因为它更通用.

The above code works because Int conforms to CustomStringConvertible, while NSError conforms to Error. Any would've also work instead of Error as it's even more generic.

现在我们已经确定了这一点,让我们看看在您的两个代码块中发生了什么.

Now that we established that, let's see what happens in your two blocks of code.

第一个块尝试将更具体的参数闭包分配给不太具体的闭包,这不遵循方差规则,因此无法编译.

The first block tries to assign a more specific argument closure to a less specific one, and this doesn't follow the variance rules, thus it doesn't compile.

第二个代码块怎么样?我们处于与第一个块中类似的场景:带有一个参数的闭包.

How about the second block of code? We are in a similar scenario as in the first block: closures with one argument.

  • 我们知道 StringVoidAny 更具体,因此我们可以将其用作返回值
  • (Int) ->Void(Any) -> 更具体.Void(闭包变化规则),所以我们可以用它作为参数
  • we know that String, or Void, is more specific that Any, so we can use it as return value
  • (Int) -> Void is more specific than (Any) -> Void (closure variance rules), so we can use it as argument

遵守闭包变化,因此 intResolverstringResolveranyResolver 的兼容匹配.这听起来有点违反直觉,但仍然遵循编译规则,并且允许赋值.

The closure variance is respected, thus intResolver and stringResolver are a compatible match for anyResolver. This sounds a little bit counter-intuitive, but still the compile rules are followed, and this allows the assignment.

然而,如果我们想使用闭包作为泛型参数,事情就变得复杂了,方差规则不再适用,这是因为 Swift 泛型(除了少数例外)在其类型方面是不变的:MyGenericType<即使 B: A 也无法将 B> 分配给 MyGenericType.例外是标准库结构,例如 OptionalArray.

Things complicate however if we want to use closures as generic arguments, the variance rules no longer apply, and this due to the fact that Swift generics (with few exceptions) are invariant in respect to their type: MyGenericType<B> can't be assigned to MyGenericType<A> even if B: A. The exceptions are standard library structs, like Optional and Array.

这篇关于类型转换/多态如何在 Swift 中使用这种嵌套的闭包类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

Why local notification is not firing for UNCalendarNotificationTrigger(为什么没有为UNCalendarNotificationTrigger触发本地通知)
Pushing UIViewController above UITabBar(将UIView控制器推送到UITabBar上方)
Dropbox Files.download does not start when number of files in folder is gt; 1000(当文件夹中的文件数为1000时,Dropbox Files.Download不会启动)
appearance().setBackgroundImage Not Working On Custom Class(外观().setBackoundImage在自定义类上不起作用)
Show/Hide barButtonItem(显示/隐藏barButtonItem)
java.lang.IllegalStateException: SimpleTypeImpl should not be created for error type(异常:不应为错误类型创建SimpleTypeImpl)