Swift 方法调度很奇怪

问题描述 投票:0回答:1

为什么操场上的结果这么奇怪? 那么如此奇怪的调度机制又是什么呢?

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'

为什么行为如此奇怪?

swift methods dynamic dispatch
1个回答
0
投票

这是一种“非常古老”、有争议的行为。简短的回答是:不要这样做。关于这是一个错误还是一个设计选择存在很多争议。 我个人的观点是,这应该是一个编译器错误,或者至少是一个警告。 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)") } }

(但你感到惊讶是对的。多年来人们对此感到惊讶是有道理的。)

© www.soinside.com 2019 - 2024. All rights reserved.