【问题标题】:Why is typecasting necessary when checking types in loops?为什么在检查循环中的类型时需要进行类型转换?
【发布时间】:2019-11-18 21:35:00
【问题描述】:

我试图更深入地理解类型转换,但不明白为什么在这个例子中它是必要的:

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 循环中“宠物”的隐式类型。我假设它只是根据数组中项目的类型来猜测类型,在我们的例子中是一个对象。

【问题讨论】:

  • 与你关于投射的问题并不真正相关,但你也可以将你的循环写为for case let pet as Dog in pets { ... },你不必在循环内进行任何投射
  • @dan 看起来干净多了。有什么缺点吗?我不会这么想,但我很好奇你是否知道。

标签: swift loops class typecasting-operator


【解决方案1】:

当你运行这一行时

print(type(of: pets))

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

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

二元运算符“==”不能应用于“动物”和“狗”类型的操作数

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

【讨论】:

  • 所以基本错误是你不能在类上使用比较'=='运算符,对吗?你知道这是为什么吗?
  • 是的,通常的方式是 is 运算符,例如if pet is Dog 但这也不会强制转换类型。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

    那么,当您询问if pet is Dog { ... } 时,您只是根据该语句检索一个布尔值,但它不会使编译器将pet 引用为Dog
    相反,当您说if let dog = pet as? Dog { ... } 时,您正在创建一个Dog? 类型的新值,这使得编译器将其称为Dog

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-22
      相关资源
      最近更新 更多