为什么操场上的结果这么奇怪? 那么如此奇怪的调度机制又是什么呢?
class A {
func execute(param: Int = 123) {
print("A: \(param)")
}
}
class B: A {
override func execute(param: Int = 456) {
print("B: \(param)")
}
}
let instance: A = B()
instance.execute()
// print B: 123
我看了 SIL 文件,但看起来还不错。 Vtables 看起来也不错。
// main
sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
alloc_global @riddle.instance : riddle.A // id: %2
%3 = global_addr @riddle.instance : riddle.A : $*A // users: %9, %8
%4 = metatype $@thick B.Type // user: %6
// function_ref B.__allocating_init()
%5 = function_ref @riddle.B.__allocating_init() -> riddle.B : $@convention(method) (@thick B.Type) -> @owned B // user: %6
%6 = apply %5(%4) : $@convention(method) (@thick B.Type) -> @owned B // user: %7
%7 = upcast %6 : $B to $A // user: %8
store %7 to %3 : $*A // id: %8
%9 = load %3 : $*A // users: %12, %13
// function_ref default argument 0 of A.execute(param:)
%10 = function_ref @default argument 0 of riddle.A.execute(param: Swift.Int) -> () : $@convention(thin) () -> Int // user: %11
%11 = apply %10() : $@convention(thin) () -> Int // user: %13
%12 = class_method %9 : $A, #A.execute : (A) -> (Int) -> (), $@convention(method) (Int, @guaranteed A) -> () // user: %13
%13 = apply %12(%11, %9) : $@convention(method) (Int, @guaranteed A) -> ()
%14 = integer_literal $Builtin.Int32, 0 // user: %15
%15 = struct $Int32 (%14 : $Builtin.Int32) // user: %16
return %15 : $Int32 // id: %16
} // end sil function 'main'
为什么行为如此奇怪?
这是一种“非常古老”、有争议的行为。简短的回答是:不要这样做。关于这是一个错误还是一个设计选择存在很多争议。 我个人的观点是,这应该是一个编译器错误,或者至少是一个警告。 IMO,B 中的函数是不同的函数,因此不会覆盖 A(所以
override
应该是一个错误)。或者它是具有不同签名的“相同”函数,这也应该是一个错误。
但事实就是如此,我怀疑是否会有人对修复它有太大兴趣。继承不是 Swift 中的首选方法,大多数新功能都侧重于使用结构、枚举或参与者的更首选方法。与大多数涉及默认值的问题一样,解决方案始终记住它们实际上是更明确语法的简写:
class A {
func execute() {
execute(param: 123)
}
func execute(param: Int) {
print("A: \(param)")
}
}
class B: A {
override func execute() {
execute(param: 456)
}
override func execute(param: Int) {
print("B: \(param)")
}
}
(但你感到惊讶是对的。多年来人们对此感到惊讶是有道理的。)