在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
上调用它,则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。调度静态方法
( 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:)
表达式来访问该实例的动态,运行时类型作为值,...
我不知道校正:请参阅Hamish的答案在静态和类方法中。static
方法的区别(这是final
并且不能在子类中覆盖)。