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

Swift调用静态方法:类型(of:self)与显式类名,swift,static-methods,Swift,Static Methods,在swift中,实例func不能调用static/class func,除非在方法调用前加上类名。或者您可以使用类型(of:self),例如 class Foo { static func doIt() { } func callIt() { Foo.doIt() // This works type(of: self).doIt() // Or this doIt() // This doesn't compile (unre

在swift中,实例
func
不能调用
static/class func
,除非在方法调用前加上类名。或者您可以使用
类型(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)
    }
}
我的问题是,这里有什么区别? 这只是编码风格的问题,还是存在一些差异,例如静态或动态调度


如果只是编码样式,那么首选的样式是什么?

对于
方法,如果方法是 在子类中重写:

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语言参考中:

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

我不知道
静态
方法(即
最终
并且不能在子类中重写)。 更正:请参阅以了解差异
在静态方法和类方法中。

有两个主要区别

1.静态方法中的
self
值 调用静态方法的元类型在方法中可用作
self
(它只是作为隐式参数传递)。因此,如果调用
doIt()
on,
self
将是实例的动态元类型。如果您在
Foo
上调用它,
self
将是
Foo.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.静态法的调度 (这个,但我想我会为了完成而添加它。)

对于在子类中重写的
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

我不相信有任何动态调度。我们不在Objective-C世界中,因为没有
@objc
动态
、或
NSObject
继承。@JAL实际上在引擎盖下(至少当包含Obj-C运行时时时是这样)。“纯”Swift也有动态调度功能(想想协议)–这不仅仅是一个Obj-C功能。@Hamish我知道Swift类继承自SwiftObject,但同样适用于开源运行时(不包括协议)?@JAL Yeah,我刚想编辑我的评论,注意到–我没有详细研究开源运行时,但我不相信Swift类是基于Obj-C类的,因为没有Obj-C运行时。请按照苹果的建议来思考这个问题:
static
class
方法的区别在于方法内部的
self
的值——请看我的答案:)@Hamish:是的,这是一个很好的观点,我没有想到这一点。