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
}
dog
是Dog
类型,但是编译器不知道在运行的时候,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
?" 它可能会说。
我很好奇 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
}
dog
是Dog
类型,但是编译器不知道在运行的时候,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
?" 它可能会说。