Swift 中的类型检查如何工作

How typechecking works in Swift

我很好奇 Swift 的类型检查是如何工作的,我尝试了一下并创建了一个 Living class 和一个 Animal class 继承自 Living class。 Cat class 继承自 Animal class,而 Dog class 没有任何父级 class.

到目前为止我的 class 层次结构:

class Living {
  let heartRatePerMin: Int
  init(heartRatePerMin: Int) {
      self.heartRatePerMin = heartRatePerMin
  }
}

class Animal: Living {
  let name: String

  init(name: String, heartRatePerMin: Int) {
      self.name = name
      super.init(heartRatePerMin: heartRatePerMin)
  }
}

class Cat: Animal {
  let meowsPerHour: Int

  init(meowsPerHour: Int, name: String) {
      self.meowsPerHour = meowsPerHour
      super.init(name: name, heartRatePerMin: 60)
  }
}

class Dog {
  let runningSpeed: Int

  init(runningSpeed : Int) {
      self.runningSpeed = runningSpeed
  }
}

首先,当我创建动物、狗和猫的实例时。我收到关于检查是否总是失败或成功的警告。我检查类型和获取警告的方式:

let animal = Animal(name: "Daisy", heartRatePerMin: 80)
let dog = Dog(runningSpeed: 2)
let cat = Cat(meowsPerHour: 10, name: "Smokey")

    if animal is Animal {
        //Warning: 'is' test always true
    }

    if dog is Animal {
        //Warning: Cast from 'Dog' to unrelated type 'Animal' always fails
    }

    if cat is Animal {
        //Warning: 'is' test always true
    }

    if cat is Living {
        //Warning: 'is' test always true
    }

到目前为止,我相信编译器会检查给定对象 class 是否具有对正在检查的类型的继承,并且可以发出警告。

然后我创建了一个空的 Grumpy 协议:

protocol Grumpy {

}

在那之后,我从我的 Cat class 符合 Grumpy,但我没有从我的 Dog class.

符合

现在,当我如下检查我的对象(猫和狗)的类型是否为 Grumpy 时,我收到 cat 的警告,因为 Cat class 符合 Grumpy 协议,但是我没有收到任何关于狗的警告。它什么也没说。但是当我检查 dog 是否是上面的 Animal 类型时,它发出警告说它总是会失败。为什么它不能为这种情况提供相同的信息?

    if cat is Grumpy {
        //Warning: 'is' test is always true
    }

    if dog is Grumpy {
        //Nothing
    }

然后鉴于我缺乏 CS 和 Swift 知识,我还尝试做一些其他事情来查看它的行为方式,我创建了一个 Any 的数组作为 anyArray。然后创建一个变量 unknown,将 cat 转换为 Any 等于 unknown。然后将 unknown 附加到 anyArray。之后,我尝试输入检查 anyArray 的第一个索引是否为 Cat 类型,但同样没有警告:

    var anyArray = [Any]()
    let unknown = cat as Any
    anyArray.append(unknown)

    if anyArray[0] is Cat {
        //Nothing.
    }

所以考虑到我尝试过的所有事情,我很好奇编译时间和 运行 时间的类型检查是如何工作的?我知道这是一个有点长的问题,但任何答案将不胜感激。

我假设您知道以下内容是有效的以及原因:

// although living is of type Living, it stores an instance of Cat at runtime
let living: Living =  Cat(meowsPerHour: 10, name: "Smokey")

让我们先检查一下:

if dog is Grumpy {
    //Nothing
}

dogDog类型,但是编译器不知道在运行的时候,dog会不会存储[=15=的子类],这确实符合 Grumpy。如果像这样分配 dog,则 if 语句将是 运行:

class GrumpyDog : Dog, Grumpy {
    // ...
}

dog = GrumpyDog(...)

if anyArray[0] is Cat {
    //Nothing.
}

这是因为 anyArray[0] 的类型是 Any。编译器不够聪明,无法知道在 运行 时,anyArray[0] 存储了一个 Cat。因此,不能确定 is 的计算结果为真。 "What if it actually is a Dog?" 它可能会说。