Swift中的static func和class 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是用于结构体和枚举的静态函数,还是用于类和协议的类? 还有其他的区别吗? 在语法本身有这种区别的基本原理是什么?

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

协议使用class关键字,但不排除实现协议的结构,它们只是使用static而不是。 类被选为协议,所以不必有第三个关键字来表示静态或类。

来自Chris Lattner的这个话题:

我们考虑统一的语法(例如使用“types”作为关键字),但这并不简单的事情。 关键字“class”和“static”对熟悉性很有帮助,而且相当具有描述性(一旦你了解了+方法的工作原理),并为可能为类添加真正的静态方法打开了大门。 这个模型的主要缺点是协议必须select一个关键字(我们select“类”),但总的来说,这是正确的折衷。

这里有一个代码片断,它显示了一些类函数的重载行为:

 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 

更清楚的是,我在这里举个例子,

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

staticclass final相同

因为它是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" } } 

要声明typesvariables属性,请使用static声明修饰符标记声明。 类可以使用class声明修饰符标记types计算的属性,而不是允许子类覆盖超类的实现。 types属性在“types属性”中讨论。

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

来源: Swift编程语言 – typesvariables属性

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

TL; DR 在这里输入图像说明

正如你所看到的,在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." 

从Swift2.0开始,苹果说:

“当你在一个协议中定义它们的时候,总是用static关键字来定义types属性的要求,即使types属性需求可以用class或者static关键字作为前缀,

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

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

主要区别在于结构是值types,类是参考types。

当您创build一个值types的副本时,它会将您正在复制的所有数据复制到新variables中。 他们是两个分开的东西,改变一个不会影响另一个

在创build引用types的副本时,新variables指向与正在复制的内容相同的内存位置。 这意味着改变一个会改变另一个,因为它们都指向相同的内存位置