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

Jea*_*let 308 static class swift

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

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

protocol BooleanLiteralConvertible {
    typealias BooleanLiteralType
    class func convertFromBooleanLiteral(value: BooleanLiteralType) -> Self
}
Run Code Online (Sandbox Code Playgroud)

定义为的成员函数与定义为的static func另一个成员函数之间有什么区别class func?它只是static用于结构和枚举的静态函数,以及class类和协议吗?还有其他人应该知道的差异吗?在语法本身中有这种区别的理由是什么?

Jak*_*Lin 226

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

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

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

  /* same as above
  final class func func2() -> String {
    return "func2"
  }
  */
}
Run Code Online (Sandbox Code Playgroud)

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"
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 你是冠军,很棒的答案..我正在寻求这种差异..杰克! (17认同)
  • 完善.令人印象深刻. (5认同)
  • 这应该标记为正确的答案.干净整洁! (5认同)

Con*_*nor 218

是静态用于结构和枚举的静态函数,还是用于类和协议的类?

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

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

来自Chris Lattner关于这个主题:

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

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

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
Run Code Online (Sandbox Code Playgroud)

  • 啊啊,非常重要的一点是动态调度类函数!但你能提供这样的例子吗?你必须在某个地方写出类名,对吗?那么为什么不静态选择那个类的实现呢? (4认同)
  • “动态调度”是什么意思? (3认同)
  • 我可以在这里提供一个更简单的答案链接吗?http://stackoverflow.com/questions/29636633/static-vs-class-functions-variables-in-swift-classes (2认同)

Nho*_*yen 71

我在操场上做了一些实验并得出了一些结论.

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."
Run Code Online (Sandbox Code Playgroud)

  • 不是`class func`可以覆盖吗? (27认同)
  • 如果您尝试覆盖静态方法,则会出现错误.但是你可以*覆盖一个类方法.看到接受的答案 (8认同)
  • 你的例子没有涵盖在另一个答案中提到的主要区别:动态调度`class`函数与`静态`函数的静态绑定. (7认同)
  • `class func`是可以覆盖的.我会投票否则; 热爱研究和榜样! (7认同)
  • 对理解函数的很好解释。 (2认同)

Nex*_*xD. 53

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

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

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

  • 问题是询问'static func'和'class func'.它不是询问类型属性.所以这并没有回答这个问题 - 尽管在属性方面了解这些关键字的背景也很重要. (4认同)

Mil*_*lad 14

根据苹果发布的Swift 2.2 Book:

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


Reh*_*han 11

这个例子将清除每个方面!

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.
 */
Run Code Online (Sandbox Code Playgroud)

输出: 输出所有类型的函数


Jac*_*cky 10

从Swift2.0开始,Apple说:

"在协议中定义类型属性要求时,始终使用static关键字作为前缀类型属性要求.即使类型属性要求在类实现时可以使用类或静态关键字作为前缀,此规则也适用:"


Hab*_*man 6

无论是静态关键字,让我们的方法附加到类而不是类的实例。例如,您可以创建一个具有名称和年龄等属性的 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
      }
  }
Run Code Online (Sandbox Code Playgroud)