在Swift中,嵌套/闭包类型如何进行类型转换/多态? [英] How does typecasting/polymorphism work with this nested, closure type in Swift?

查看:125
本文介绍了在Swift中,嵌套/闭包类型如何进行类型转换/多态?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道(Int)->无效无法强制转换为(任何)->无效

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'类型的值转换为指定的类型
'(Any)-> 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

推荐答案

这一切与方差和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 ,如果 Res1:Res2 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 任何也可以代替错误,因为它更通用。

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.

第一个块尝试为

第二个代码块怎么样?这是一个较不具体的代码,它不遵循方差规则,因此无法编译。我们处于与第一个块类似的场景:使用一个参数的闭包。

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


  • 我们知道 String Void Any 更具体,因此我们可以将其用作返回值

  • (Int)->无效(任何)->更具体无效(闭合方差规则),因此我们可以将其用作参数

  • 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

尊重闭合方差,因此 intResolver stringResolver anyResolver 的兼容匹配项。这听起来有点违反直觉,但是仍然遵循编译规则,并且允许进行赋值。

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> 即使 B:A 也被分配给 MyGenericType< A> 。标准库结构除外,例如 Optional Array

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中,嵌套/闭包类型如何进行类型转换/多态?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆