Swift调用静态方法:类型(OF:self)与显式类名称



在Swift中,实例func不能在不将方法调用之前使用类名来调用static/class func。或者您可以使用type(of: self),例如

class Foo {
    static func doIt() { }
    func callIt() {
        Foo.doIt() // This works
        type(of: self).doIt() // Or this
        doIt() // This doesn't compile (unresolved identifier)
    }
}

我的问题是,这里有什么区别?这只是编码样式的问题,还是有一些区别,例如进行静态或动态调度?

如果仅是编码样式,则首选样式是什么?

有两个主要区别。

1。静态方法内self的值

您称之为静态方法的元类型在方法中可用于self(简单地将其作为隐式参数传递)。因此,如果您在type(of: self)上调用doIt(),则self将是实例的 dynamic metatype。如果您在Foo上调用它,则selfFoo.self

class Foo {
    static func doIt() {
        print("hey I'm of type (self)")
    }
    func callDoItOnDynamicType() {
        type(of: self).doIt() // call on the dynamic metatype of the instance.
    }
    func classDoItOnFoo() {
        Foo.doIt() // call on the metatype Foo.self.
    }
}
class Bar : Foo {}
let f: Foo = Bar()
f.callDoItOnDynamicType() // hey I'm of type Bar
f.classDoItOnFoo()        // hey I'm of type Foo

这种差异可以是对工厂方法的重要性,因为它确定了您创建的实例类型。

class Foo {
    required init() {}
    static func create() -> Self {
        return self.init()
    }
    func createDynamic() -> Foo {
        return type(of: self).create()
    }
    func createFoo() -> Foo {
        return Foo.create()
    }
}
class Bar : Foo {}
let f: Foo = Bar()
print(f.createDynamic()) // Bar
print(f.createFoo())     // Foo

2。调度静态方法

Martin已经介绍了这一点,但我想我会为了完成而添加它。

对于子类覆盖的class方法,您调用该方法的元类型的值确定要调用的实现。

如果在编译时已知的元类型(例如Foo.doIt()),Swift可以静态地派遣调用。但是,如果在运行时(例如type(of: self))上调用该方法,该方法将 用于元类型值的正确实现。

class Foo {
    class func doIt() {
        print("Foo's doIt")
    }
    func callDoItOnDynamicType() {
        type(of: self).doIt() // the call to doIt() will be dynamically dispatched.
    }
    func classDoItOnFoo() {
        Foo.doIt() // will be statically dispatched.
    }
}

class Bar : Foo {
    override class func doIt() {
        print("Bar's doIt")
    }
}
let f: Foo = Bar()
f.callDoItOnDynamicType() // Bar's doIt
f.classDoItOnFoo()        // Foo's doIt

对于class方法,如果该方法为在子类中覆盖:

class Foo {
    class func doIt() {
        print("Foo doit")
    }
    func callViaClassname() {
        Foo.doIt()
    }
    func callViaTypeOf() {
        type(of: self).doIt()
    }
}
class Bar: Foo {
    override class func doIt() {
        print("Bar doit")
    }
}
Bar().callViaClassname() // Foo doit
Bar().callViaTypeOf() // Bar doit

在Swift语言参考中的"类型"中也记录了这一点:

您可以使用类型的实例使用type(of:)表达式来访问该实例的动态,运行时类型作为值,...

我不知道static方法的区别(这是final并且不能在子类中覆盖)。校正:请参阅Hamish的答案在静态和类方法中。

最新更新