在检查循环中的类型时,为什么必须进行类型转换?

时间:2019-11-18 21:35:00

标签: swift loops class typecasting-operator

我试图更深入地了解类型转换,但不了解为什么在此示例中必须这样做:

class Animal { }
class Fish: Animal { }

class Dog: Animal {
    func makeNoise() {
        print("Woof!")
    }
}

let pets = [Fish(), Dog(), Fish(), Dog()]

我正在阅读该代码以检查上述数组中的类型,我需要运行以下代码:

for pet in pets {
    if let dog = pet as? Dog {
        dog.makeNoise()
    }
}

并且以下代码将崩溃:

for pet in pets {
    if pet == Dog() {
        pet.makeNoise()
    }
}

它返回以下错误:

error: Learn Swift.playground:24:13: error: value of type 'Animal' has no member 'makeNoise'
        pet.makeNoise()
        ~~~ ^~~~~~~~~

那是为什么?难道最后那段代码只是检查数组中的项是否是Dog()?

当前,我的猜测是我不完全了解for循环中“ pet”的隐式类型。我假设它只是根据数组中项目的类型猜测类型,在我们的例子中是对象。

3 个答案:

答案 0 :(得分:1)

检查数组pets的类型:应为[Animal] /。动物无法发出声音,因此您需要明确检查它是否为狗。本质上,您已经将Dog的类型与其他Animals装在异类数组中而丢失了。在动物上调用makeNoise()是没有意义的,因此编译器会强制您在调用Dog之前检查数组的元素实际上是makeNoise()

答案 1 :(得分:1)

运行此行

print(type(of: pets))

它显示Array<Animal>。基类是数组中各项的公分母。

在第二个示例中,您应该遇到另一个编译器错误

  

二进制运算符'=='不能应用于类型为'动物'和'狗'的操作数

尽管如此,但没有类型强制转换pet仍然Animal,并且'Animal'没有成员'makeNoise'

答案 2 :(得分:0)

首先,在检查实例类型时使用is键盘。例如if pet is Dog { ... },您当前正在冗余地初始化它的新对象。

因此,当您问if pet is Dog { ... }时,您只是在基于该语句检索布尔值,但这并没有使编译器将pet称为Dog
相反,当您说if let dog = pet as? Dog { ... }时,您正在创建类型为Dog?的新值,这使编译器将其称为Dog