在Swift中静态func和类func的区别是什么?

我可以在Swift库中看到这些定义:

extension Bool : BooleanLiteralConvertible {
static func convertFromBooleanLiteral(value: Bool) -> Bool
}


protocol BooleanLiteralConvertible {
typealias BooleanLiteralType
class func convertFromBooleanLiteral(value: BooleanLiteralType) -> Self
}

定义为static func的成员函数和定义为class func的成员函数之间有什么区别?是不是简单地说,static用于结构和枚举的静态函数,而class用于类和协议?还有其他不同之处吗?在语法本身中有这种区别的基本原理是什么?

130758 次浏览

是不是简单地说,static是用于结构体和枚举的静态函数,class是用于类和协议?

这是主要的区别。其他一些不同之处在于类函数是动态分派的,并且可以被子类覆盖。

协议使用class关键字,但它不排除实现协议的结构,而是使用static。Class是为协议选择的,这样就不需要第三个关键字来表示静态或类。

下面是克里斯·拉特纳对这个话题的看法:

我们考虑统一语法(例如使用“type”作为关键字),但这实际上并不能简化事情。关键字“类”和“静态”有助于熟悉并具有相当的描述性(一旦您理解了+方法的工作方式),并为潜在地向类添加真正的静态方法打开了大门。这个模型的主要奇怪之处在于协议必须选择一个关键字(我们选择了“类”),但总的来说,这是正确的权衡。

下面是一个片段,展示了类函数的一些重写行为:

class MyClass {
class func myFunc() {
println("myClass")
}
}


class MyOtherClass: MyClass {
override class func myFunc() {
println("myOtherClass")
}
}


var x: MyClass = MyOtherClass()
x.dynamicType.myFunc() //myOtherClass
x = MyClass()
x.dynamicType.myFunc() //myClass

要声明类型变量属性,请使用static声明修饰符标记声明。类可以用class声明修饰符标记类型计算属性,以允许子类重写超类的实现。类型属性在类型属性中讨论。

< p > 请注意
在类声明中,关键字static与同时使用classfinal声明修饰符标记声明具有相同的效果

来源:Swift编程语言-类型变量属性

来自Swift2.0,苹果表示:

“当你在协议中定义类型属性需求时,总是用static关键字作为前缀。当类实现时,即使类型属性要求可以用class或static关键字作为前缀,该规则也适用:"

为了更清楚,我举个例子,

class ClassA {
class func func1() -> String {
return "func1"
}
    

static func func2() -> String {
return "func2"
}
}


/* same as above
final class func func2() -> String {
return "func2"
}
*/

static funcfinal class func相同

因为它是final,所以我们不能在子类中重写它,如下所示:

class ClassB : ClassA {
override class func func1() -> String {
return "func1 in ClassB"
}
    

// ERROR: Class method overrides a 'final` class method
override static func func2() -> String {
return "func2 in ClassB"
}
}

我在操场上做了一些实验,得到了一些结论。

< >强TL,博士 enter image description here < / p >

如你所见,在class的情况下,使用class funcstatic func只是一个习惯问题。

游乐场的例子,并附有解释:

class Dog {
final func identity() -> String {
return "Once a woofer, forever a woofer!"
}


class func talk() -> String {
return "Woof woof!"
}


static func eat() -> String {
return "Miam miam"
}


func sleep() -> String {
return "Zzz"
}
}


class Bulldog: Dog {
// Can not override a final function
//    override final func identity() -> String {
//        return "I'm once a dog but now I'm a cat"
//    }


// Can not override a "class func", but redeclare is ok
func talk() -> String {
return "I'm a bulldog, and I don't woof."
}


// Same as "class func"
func eat() -> String {
return "I'm a bulldog, and I don't eat."
}


// Normal function can be overridden
override func sleep() -> String {
return "I'm a bulldog, and I don't sleep."
}
}


let dog = Dog()
let bullDog = Bulldog()


// FINAL FUNC
//print(Dog.identity()) // compile error
print(dog.identity()) // print "Once a woofer, forever a woofer!"
//print(Bulldog.identity()) // compile error
print(bullDog.identity()) // print "Once a woofer, forever a woofer!"


// => "final func" is just a "normal" one but prevented to be overridden nor redeclared by subclasses.




// CLASS FUNC
print(Dog.talk()) // print "Woof woof!", called directly from class
//print(dog.talk()) // compile error cause "class func" is meant to be called directly from class, not an instance.
print(Bulldog.talk()) // print "Woof woof!" cause it's called from Bulldog class, not bullDog instance.
print(bullDog.talk()) // print "I'm a bulldog, and I don't woof." cause talk() is redeclared and it's called from bullDig instance


// => "class func" is like a "static" one, must be called directly from class or subclassed, can be redeclared but NOT meant to be overridden.


// STATIC FUNC
print(Dog.eat()) // print "Miam miam"
//print(dog.eat()) // compile error cause "static func" is type method
print(Bulldog.eat()) // print "Miam miam"
print(bullDog.eat()) // print "I'm a bulldog, and I don't eat."


// NORMAL FUNC
//print(Dog.sleep()) // compile error
print(dog.sleep()) // print "Zzz"
//print(Bulldog.sleep()) // compile error
print(bullDog.sleep()) // print "I'm a bulldog, and I don't sleep."

根据苹果公司发布的Swift 2.2 Book:

通过在方法的func关键字之前写入static关键字来指示类型方法。类也可以使用class关键字以允许子类重写超类对该方法的实现。”

这被称为类型方法,并且像实例方法一样使用点语法调用。但是,在类型上调用类型方法,而不是在该类型的实例上调用类型方法。下面是如何在一个名为SomeClass的类上调用类型方法:

这个例子将清楚每一个方面!

import UIKit


class Parent {
final func finalFunc() -> String { // Final Function, cannot be redeclared.
return "Parent Final Function."
}


static func staticFunc() -> String { // Static Function, can be redeclared.
return "Parent Static Function."
}


func staticFunc() -> String { // Above function redeclared as Normal function.
return "Parent Static Function, redeclared with same name but as non-static(normal) function."
}


class func classFunc() -> String { // Class Function, can be redeclared.
return "Parent Class Function."
}


func classFunc() -> String { // Above function redeclared as Normal function.
return "Parent Class Function, redeclared with same name but as non-class(normal) function."
}


func normalFunc() -> String { // Normal function, obviously cannot be redeclared.
return "Parent Normal Function."
}
}


class Child:Parent {


// Final functions cannot be overridden.


override func staticFunc() -> String { // This override form is of the redeclared version i.e: "func staticFunc()" so just like any other function of normal type, it can be overridden.
return "Child Static Function redeclared and overridden, can simply be called Child Normal Function."
}


override class func classFunc() -> String { // Class function, can be overidden.
return "Child Class Function."
}


override func classFunc() -> String { // This override form is of the redeclared version i.e: "func classFunc()" so just like any other function of normal type, it can be overridden.
return "Child Class Function, redeclared and overridden, can simply be called Child Normal Function."
}


override func normalFunc() -> String { // Normal function, can be overridden.
return "Child Normal Function."
}
}


let parent = Parent()
let child = Child()


// Final
print("1. " + parent.finalFunc())   // 1. Can be called by object.
print("2. " + child.finalFunc())    // 2. Can be called by object, parent(final) function will be called.
// Parent.finalFunc()               // Cannot be called by class name directly.
// Child.finalFunc()                // Cannot be called by class name directly.


// Static
print("3. " + parent.staticFunc())  // 3. Cannot be called by object, this is redeclared version (i.e: a normal function).
print("4. " + child.staticFunc())   // 4. Cannot be called by object, this is override form redeclared version (normal function).
print("5. " + Parent.staticFunc())  // 5. Can be called by class name directly.
print("6. " + Child.staticFunc())   // 6. Can be called by class name direcly, parent(static) function will be called.


// Class
print("7. " + parent.classFunc())   // 7. Cannot be called by object, this is redeclared version (i.e: a normal function).
print("8. " + child.classFunc())    // 8. Cannot be called by object, this is override form redeclared version (normal function).
print("9. " + Parent.classFunc())   // 9. Can be called by class name directly.
print("10. " + Child.classFunc())   // 10. Can be called by class name direcly, child(class) function will be called.


// Normal
print("11. " + parent.normalFunc())  // 11. Can be called by object.
print("12. " + child.normalFunc())   // 12. Can be called by object, child(normal) function will be called.
// Parent.normalFunc()               // Cannot be called by class name directly.
// Child.normalFunc()                // Cannot be called by class name directly.


/*
Notes:
___________________________________________________________________________
|Types------Redeclare------Override------Call by object------Call by Class|
|Final----------0--------------0---------------1------------------0-------|
|Static---------1--------------0---------------0------------------1-------|
|Class----------1--------------1---------------0------------------1-------|
|Normal---------0--------------1---------------1------------------0-------|
---------------------------------------------------------------------------


Final vs Normal function: Both are same but normal methods can be overridden.
Static vs Class function: Both are same but class methods can be overridden.
*/
< p >输出: 输出所有类型的函数 < / p >

静态关键字都允许我们将方法附加到类而不是类的实例。例如,您可以创建一个具有名称和年龄等属性的Student类,然后创建一个静态方法numberOfStudents,该方法由Student类本身而不是单个实例拥有。

静态的不同之处在于它们支持继承的方式。当你创建一个静态方法时,它被类拥有,不能被子类改变,而当你使用类时,它可能会在需要时被覆盖。

下面是一个示例代码:

class Vehicle {
static func getCurrentSpeed() -> Int {
return 0
}
    

class func getCurrentNumberOfPassengers() -> Int {
return 0
}
}


class Bicycle: Vehicle {
//This is not allowed
//Compiler error: "Cannot override static method"
//static override func getCurrentSpeed() -> Int {
//return 15
//}
    

class override func getCurrentNumberOfPassengers() -> Int {
return 1
}
}