打开阵列类型

use*_*037 5 switch-statement swift

概观

我想通过匹配数组类型来使用switch语句.我有以下课程.

类:

class A {}    
class B : A {}
Run Code Online (Sandbox Code Playgroud)

打开单值工作:

let a : A = B()

switch a {
case let b as B:
    print("b = \(b)")
default:
    print("unknown type")
}
Run Code Online (Sandbox Code Playgroud)

打开数组(编译错误):

let aArray : [A] = [B(), B()]

switch aArray {
case let bArray as [B] :
    print("bArray = \(bArray)")
default:
    print("unknown type")
}
Run Code Online (Sandbox Code Playgroud)

错误:

Downcast pattern value of type '[B]' cannot be used
Run Code Online (Sandbox Code Playgroud)

注意:Swift 4上测试过

题:

  • 我怎样才能做到这一点?

Ham*_*ish 7

在Swift 4.1中,您会收到更好的错误消息(感谢#11441):

收集铸造模式中的向下转换未实现; 使用显式向下转换为"[B]"

简而言之,您正在尝试一些尚未完全实现的编译器,其中的进度由错误SR-5671跟踪.

但是,您可以Any在执行强制转换之前通过强制转换来解决此限制:

class A {}
class B : A {}

let aArray : [A] = [B(), B()]

switch aArray /* or you could say 'as Any' here depending on the other cases */ {
case let (bArray as [B]) as Any:
  print("bArray = \(bArray)")
default:
  print("unknown type")
}

// bArray = [B, B]
Run Code Online (Sandbox Code Playgroud)

为什么这样做?首先,有点背景.数组,字典和集合由Swift的转换机制专门处理 - 尽管是泛型类型(默认情况下是不变的),Swift允许您在不同元素类型的集合之间进行转换(有关详细信息,请参阅此问答).

实现这些转换的函数驻留在标准库中(例如,此处Array实现在此处).在编译时,斯威夫特将尝试确定收集向下转换(例如,[A][B]在你的例子),所以它可以直接调用上述转换功能,并避免做一个全面通过斯威夫特运行时动态转换.

但问题是这种专用逻辑没有实现收集向下转换模式(例如在您的示例中),因此编译器会发出错误.通过首先强制执行Any,我们强制Swift执行一个完全动态的强制转换,它会在运行时调度,最终会调用前面提到的转换函数.

虽然为什么编译器不能暂时将这些强制类型转换为完全动态转换,直到必要的专用逻辑到位,但我不太确定.


DEA*_*EEF 2

对于任何有同样问题的人,它已在 Swift 5.8 中得到修复。

打开数组(原始代码)可以正常编译。

正如《Hacking with swift》中提到的,您现在可以执行以下操作:

class Pet { }
class Dog: Pet {
    func bark() { print("Woof!") }
}

func bark(using pets: [Pet]) {
    switch pets {
    case let pets as [Dog]:
        for pet in pets {
            pet.bark()
        }
    default:
        print("No barking today.")
    }
}
Run Code Online (Sandbox Code Playgroud)