Swift 中的 static func 和 class func 有什么区别?

问题描述 投票:0回答:9

我可以在 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
用于类和协议吗?还有其他需要了解的差异吗?语法本身有这种区别的理由是什么?

class static swift
9个回答
383
投票

为了更清楚,我在这里举个例子,

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 func
final 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"
    }
}

293
投票

是否简单地说 static 代表结构体和枚举的静态函数,class 代表类和协议?

这是主要区别。其他一些区别是类函数是动态调度的并且可以被子类覆盖。

协议使用 class 关键字,但它并不排除结构体实现协议,它们只是使用 static 代替。为协议选择了类,因此不必使用第三个关键字来表示静态或类。

来自 Chris Lattner 关于此主题的内容:

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

这是一个片段,显示了类函数的一些重写行为:

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

89
投票

我在游乐场做了一些实验并得到了一些结论。

TL;博士

如您所见,就

class
而言,使用
class func
static 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."

54
投票

要声明类型变量属性,请使用

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

注意
在类声明中,关键字

static
与使用
class
final
声明修饰符标记声明具有相同的效果。

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


26
投票

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

静态的不同之处在于它们支持继承的方式。当您创建静态方法时,它由类拥有,并且不能由子类更改,而当您使用类时,如果需要,它可能会被覆盖。

这是示例代码:

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 } }
    

23
投票
这个例子将清楚各个方面!

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. */

输出:


15
投票
根据苹果出版的Swift 2.2 Book:

“您可以通过在方法的 func 关键字之前写入

static

 关键字来指示类型方法。类还可以使用 
class
 关键字 
允许子类覆盖超类对该方法的实现 。”


10
投票
从 Swift2.0 开始,Apple 表示:

“在协议中定义类型属性要求时,始终使用 static 关键字作为前缀。即使类型属性要求在由类实现时可以使用 class 或 static 关键字作为前缀,但仍适用此规则:”


-7
投票
这称为类型方法,与实例方法一样使用点语法调用。但是,您是在类型上调用类型方法,而不是在该类型的实例上调用类型方法。以下是如何在名为 SomeClass 的类上调用类型方法:

© www.soinside.com 2019 - 2024. All rights reserved.